Memento Pattern with ColdFusion 9's Automatic Getters and Setters

ColdFusion , CFML Add comments

One of the (many) ways ColdFusion 9 has made developers' lives easier is by not requiring us to write accessor and mutator methods ("getters and setters") in our components. By setting accessors="true" in a component and defining some properties, we can call getProperty() and setProperty() on the component without having to actually write the methods. Rupesh Kumar has a detailed blog post on this feature.

While this can be a great time saver and unclutters our components from all those getter and setter methods, the thing I wasn't too crazy about is that when we call a setter method, the value is put into the variables scope of the component. The reason I didn't like this is that I like to isolate a component's properties from its methods. This allows me to externalize the component's state into a structure of its property values. For example, in my "old school" way of writing components, I would do this in the pseudo-constructor:

<cfset variables.instance = structNew() />

Then whenever a setter is called, the value is set into the instance structure.

<cffunction name="setFirstName" returntype="void" access="public" output="false">
    <cfargument name="firstName" type="string" required="true" />
    <cfset variables.instance.firstName = arguments.firstName />
</cffunction>

This method, then, will return a struct of name-value pairs for the component's properties:

<cffunction name="getMemento" access="public" returntype="struct" output="false" >
    <cfreturn variables.instance />
</cffunction>

There is also a corresponding setMemento method which will set the entire instance structure in the component. These methods can be used to implement the memento pattern, and I first ran into these when I started using Brian Rinaldi's Illudium PU-36 Code Generator. I have found them to be pretty useful when I code, but it bears pointing out that these methods require that an object's properties be isolated from its methods. However, when you use CF9's automatically-generated getters and setters, an object's properties are in the variables scope right along with its methods. So there's no way to neatly pass around structures of ONLY properties. To get around this I have come up with this version of the getMemento() method for CF9 components using accessors="true":

public struct function getMemento(){
    var i = "";
    var md = getMetaData( this );
    var instance = {};
    for( i=1;i <= arrayLen( md.properties ); i++ ){
        if( structKeyExists( variables,md.properties[i]["name"] ) )
            instance[md.properties[i]["name"]] = variables[md.properties[i]["name"]];
        else
            instance[md.properties[i]["name"]] = "";
    }
    return instance;
 }

Basically, I'm looping through the properties array from the object's metadata and copying values from the variables scope to an instance struct and returning it. This is the corresponding setMemento() method:

public void function setMemento( struct memento ){
    var i="";
    var md = getMetaData( this );
    for( i=1;i<=arrayLen( md.properties );i++ ){
        if ( structKeyExists( arguments.memento,md.properties[i]["name"] ) )
            variables[md.properties[i]["name"]] = arguments.memento[md.properties[i]["name"]];
    }
}

Here again I'm looping over the properties and then setting values in the variables scope from corresponding values in the struct that was passed in.

Admittedly, this is a bit of a kludge. But the end result does what I'm after, so I'm content with that. Still, I have a nagging feeling that there may be a much more straightforward way to do what I'm after. It hasn't escaped my notice that if, for example, you have a user component with properties of userID, firstName, and lastName and you do a cfdump on the object, you get this:

image of component dump

That nested PROPERTIES struct is exactly what I'm after (without the accompanying METHODS, which are collapsed in this screen shot). But no amount of experimentation has allowed me to access that PROPERTIES struct from an object dump. If anyone knows how do do that, please chime in!

4 responses to “Memento Pattern with ColdFusion 9's Automatic Getters and Setters”

  1. Henry Ho Says:
    Your getMemento() method might not work for object that extends from a CFC.

    and, what is ["name"] in setMemento()?
  2. Daniel Schmid Says:
    I did something similar which includes also "extended properties" and merged it in a abstract base component

    http://www.danielschmid.name/post.cfm/instanz-daten-aus-coldfusion-9-orm-entity-auslesen
  3. Tony Garcia Says:
    @Daniel -- yeah, it looks like you and I and James Allen in this post were thinking along the same lines:
    http://cookbooks.adobe.com/post_A_getMemento___method_when_using_implicit_getter_a-16334.html

    @Henry -- I use a recursive method to get the properties of any extended components (which I didn't talk about in this post, to keep it on one subject) but is similar to the way Daniel did it in his post or Bob Silverberg's method here:
    http://www.silverwareconsulting.com/index.cfm/2009/12/21/A-Recursive-Function-to-Gather-CFC-Metadata-for-Inherited-Properties
    Also, ["name"] is the key in a given property struct that give you the property's name.
  4. Henry Ho Says:
    CF9 GetMemento() that works with inheritance:

    http://henrylearnstorock.blogspot.com/2010/01/cf9-getmemento-that-works-with.html

Leave a Reply

Leave this field empty:

Powered by Mango Blog. Design and Icons by N.Design Studio