Elsewhere, you might create a "Customer" object that has properties like customerNumber, name, phone that are strings. You also give it a property called mailingAddress that has a type of Address (defined by the address object created earlier).
But what happens when you have to relate more than one child instance to the parent?
Suppose we're working with a set of objects like the ones shown in the diagram. Here, things are starting to get a little more complicated. We now have a parent object(car) that needs to contain several instances of our wheel object. In order to handle this, we create a wheelArray property in Car. Each wheel that needs to be on our car can now occupy a position in our array.
Lets skip ahead here and presume that all of the classes have a full set of basic getters and setters as well as a constructor that returns the object. We've also created an instance of our car object called myCar and that all of the properties have been populated with default values.
We can now reference one of the wheels and set its air pressure by doing something like this:
wheelArray = myCar.getWheelArray();
Say we now need to tell our car that the 3rd lug nut on wheel 1 is a locking lug. We could take the pattern above a step further by doing this:
lugArray = wheelArray.getLugArray;
We can continue down the chain working with setting temporary variables for a few levels of nested objects, but eventually we run into problems. I've run into problems where the referencing of objects seems to fall apart and executing setter methods doesn't change the value of the object. I think this is due to the way CF creates copies of complex objects. Deep levels only get copied by reference.
The way I've gotten around this issue is to create additional getters for properties that return arrays of objects. You require a single argument to reference a specific item in the array. In the example here, Car.cfc would get a new getter like this (note, I put all my properties into a structure called instance):
<cffunction name="getWheel" access="public" output="false" returntype="Wheel">
<cfargument name="arrayIndex" required="true" type="numeric" />
<cfreturn variables.instance.wheelArray[arguments.arrayIndex] />
We can now set the air pressure of a specific wheel without assigning the array to a temporary variable.
Setting the lug can be done in one line now, too.
I think (but I'm not sure) that this works because no arrays are getting returned by the string of components and none are getting assigned to temporary variables. There is an unbroken chain of objects being returned until we get to the last method that does the actual work. Hopefully, somebody can verify that this is the case.
It took me a long time through trial and error to figure out a way to handle this (I have another method for dealing with this that involves recursive variable assignments, but I can pretty much guarantee that it will NEVER wind up as a best practice). For me, this is one of those things that seems so simple once you know about it, but is a real time waster until you do.
For me, it seems that "reading the books" only gets me so far. Inevitably putting the concepts into practice gets more complicated when I'm trying to build a real application.
Thanks to Brendan O'Hara for his article Design Patterns in ColdFusion: Composite Pattern for getting me started.