Model-Glue, "Mixins," and Headstart

When Model-Glue 1.1 hits, you might notice something weird in the "Headstart" application template: a <cfinclude> tag in the middle of a CFC file. There's a story behind that, and it's a practical example of what people are calling a "Mixin."

[Read more on Joe Rinehart's blog]

From what I can tell, the formal name "Mixin" is coming from the Ruby camp, and it's catching on: it's supposed to be supported in C# 3.0. Well, we've had them since...the dawn of CFCs, to my knowledge.

I have...umm..."mixed" feelings over Mixins. In the world of "is-a" and "has-a," mixins are sort of a "can-do," which is why I name mine the way I do. They're likely to be used and abused, and I can see where overuse may make life hellish - but I think that's true for most programming tools.

Ok, hubbub aside, here's a practical use and example of a Mixin:

In the Model-Glue "Headstart" template I'm working on, I've got five controllers. They all use at least one CFC that gets autowired to the controller via ColdSpring. Some of them, like EmailController and ErrorController, use an EmailService CFC. So, I wind up with code like this duplicated in both Controllers:

<cffunction name="SetEmailService" access="public" returntype="void" output="false">
   <cfargument name="EmailService" required="true" type="any" />
   <cfset variables._emailService = arguments.EmailService />
</cffunction>
<cffunction name="GetEmailService" access="private" returntype="any" output="false">
   <cfreturn variables._emailService />
</cffunction>

Well, that's nice and redundant. In fact, there are three such services and a configuration management CFC that get used by the various Controllers; some use just one, some use more than one. However, they all have something in common: they're using application-level services to get something done.

Let's say each controller "can-do" use of application services. Wouldn't it be nice if there was a way I could just have all of repeated code in one place?

One approach is inheritance. ColdFusion (thankfully!) doesn't have multiple inheritance, so that's out. All of the controllers currently inherit from modelglue.core.Controller, so I could create a different subclass of modelglue.core.Controller, and point the actual controllers to that new subclass, but that gives me a code smell: I'm inheriting to share functionality, not represent an is-a relationship.

Instead of using inheritance, I'll just "mix in" that functionality.

It's, uh, really simple.

First, I take all of that redundant code, and put it in my mixin file. I'll call it UseApplicationServices.cfm, and put it under model/mixin.

Second, I'll copy all of those redundant UDFs into UseApplicationServices.cfm.

Third (and last), I'll replace all of that redundant code with the tag that started it all, <cfinclude>>:

<cfinclude template="/headstart/mixin/UseApplicationServices.cfm" />

What we've done

We've used a Mixin to say that each Controller "can-do" functionality related to public setting and private getting of application-wide services. If I need to add a new service, I can just define it in my ColdSpring XML, add a SetNewService method to my UseApplicationServices.cfm Mixin, and all of my "Mixed" Controllers now have access to it. Pretty trick, eh?

Conclusion

Mixins are powerful, but they can be somewhat dangerous. You're adding methods to your CFC on the fly, and it could become a fun jungle of figuring out just where a specific method came from: imagine multiple mixins with identically named methods!

TweetBacks
Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
© 2018 Joe Rinehart
BlogCFC was created by Raymond Camden. This blog is running version 5.9.3.006.