Flex Object Composition Car Example

Posted on July 12, 2006 | 5 comments

I read a post called “Getting a bunch of components that work together to know about each other” on “The Joy of Flex” blog by David Coletta and figured I would share how it settled in my brain. First off cohesion and coupling of classes through inheritance or composition are very fluid things. When modeling the real world you can describe the same things quite differently depending on your prespective and usage. Composition, David calls it “containment”, is a very basic part of Object Oriented development. I will use a Car for my example and try to example David’s thoughts as I understood them. Now my take on this might be off but thats the joy of software engineering.

When David calls composition containment he also uses the terms of “descendant” and “ancestor” loosly to mean the a component that is contained by another and the one containing components, respectively.

My first object in the Car example would be the Car object. It will contain the Engine, Tire, and SteeringWheel object, all ancestors of Car. Thus Car is a ancestor to Engine as the Engine is a descendant to the Car.

David talks about 4 rules that he has developed by, first is all descendants need to provide a property that the ancestor can set. The property provides the descendant with a reference back to the ancestor.

The second is that the descendants “ancestor” reference property be set in the CREATION_COMPLETE handler of the descendant. In looking at components in Flex 2 we have the “creationComplete” event or more properly for customized components the “createChildren” or “childrenCreated” functions. The later are protected methods of any component supporting the UIComponent and are for us in custom components.

The third is that you create an API of getters or public members in the top most ancestor (top-level) component for the descendants to communicate to each other. There are 2 interpertation that I come up with off the top of my head. Using the Car example the first would be that the Car class would look like this:

[code lang="javascript"]
package com.renaun.objects
{
public class Car
{
public var _engine:Engine;
public var _steeringWheel:SteeringWheel;
public var _tires:Array; // array of Tire objects
}
}
[/cc]

Here you would just get a reference to any descendant objects of the Car instance. In terms of encapsulation this is not good. You should do something more like this:

[code lang="javascript"]
package com.renaun.objects
{
public class Car
{
private var _engine:Engine;
private var _steeringWheel:SteeringWheel;
private var _tires:Array; // array of Tire objects
private var isFourWheelDrive:Boolean;

public function Car()
{
super();
_engine = new Engine();
_steeringWheel = new SteeringWheel();
_tires = new Array();
_tires.push( new Tire( "RearLeft" );
_tires.push( new Tire( "RearRight" );
_tires.push( new Tire( "FrontLeft" );
_tires.push( new Tire( "FrontRight" );
isFourWheelDrive = true;
}

// Functions to get indirect access to descendants
public function turnKey():void {
_engine.startEngine();
}

// Functions to get indirect access to descendants
public function putIntoDrive():void {
_engine.engageTranmission();
var numWheels:int = ( isFourWheelDrive ) ? 4 : 2;
for( var i:int; i < numWheels; i++ )
_tires[ i ].startTurning();
}

}
}
[/cc]

Now the putIntoDrive doesn't really just start turning wheels, but you could put other composition into the car so the Tires where part of the drive line, axles, etc... and have the composed parts have their on API that makes more sense.

The fourth rule is that any initialization code in a descendant that needs access the ancestor should be done in the setter of the descendants "ancestor" reference property. This makes sense as its the first place where you know you have a valid reference to the ancestor.

For the full code example of the 4 rules above click here.

You can view the source here.

  • mh

    why do you use super()?

  • Pingback: The Joy of Flex » Check out Renaun Erickson’s Object Composition example

  • http://www.renaun.com Renaun Erickson

    super on the class above is pointless, its was a generated class and I didn’t clean it out. It also will not hurt leaving it in.

  • http://www.colettas.org David Coletta

    Can you say more about why you prefer overriding childrenCreated() as opposed to listening for CREATION_COMPLETE? I admit that when I first started using Flex 2.0 alpha, my first instinct was to oveerride a method somewhere. I’m pretty sure I looked for a childrenCreated() protected method, didn’t find it, and just went with the event listener approach instead. I think perhaps they added childrenCreated() late in the game, after I had standardized on something else.

    But anyway, I’m curious why you think it’s more proper for a custom component to use the override approach rather than the event listener approach?

  • http://www.renaun.com Renaun Erickson

    Mostly because I read Ely Greenfield’s pdf on “Building A Flex Component”.

    http://www.onflex.org/ACDS/BuildingAFlexComponent.pdf

    He states the life cycle of the component (page 8) is as such:
    Constructor
    createChildren()
    commitProperties()
    measure()
    updateDisplayList()
    CustomEvents

    I am a little new to all this also, so my thinking is that
    creationComplete event’s definition is this

    “Dispatched when the component has finished its construction, property processing, measuring, layout, and drawing.”

    This puts the creationComplete event in at the tail end of the component lifecycle. Now for childrenCreated()’s definition:

    “Performs any final processing after child objects are created.”

    Now I should do some real tests but it makes sense to do your initializing of pointers etc… right after the children are created (either createChildren() as in Ely’s slide or childrenCreated()) so that the initialized code can be used in the rest of the Child’s lifecycle, (commitProperties(), measure(), updateDisplayList(), Custom events)

    Both methods will work its a matter of the lifecycle of the component and what you want to accomplish.

  • Marcus

    First, thanks for putting the time into creating all these examples.

    This is just an idea I had while looking through the source code.
    All your car parts extend from the ‘CompositionBase’ class to ensure that the ‘ptrCar’ property is available to be set from the ‘Car’ class by its childrenCreated() method. In this example, that’s cool and works fine, but I’d suggest you create an ‘CompositionBase’ Interface that all your car parts can implement, rather than the ‘CompositionBase’ Class they extend. (AS3 allows you to define getters and setters on Interfaces now.) That way you still know all the car parts implement the ‘ptrCar’ thingy and they have the freedom to extend from other more relevant classes. eg. Headlight.as, Blinker.as, InteriorLight.as, GloveBoxLight.as can all extend from a basic Light.as Class to get its on/off functionality as well as implement ‘CompositionBase’ so we know they all belong to our car.
    Keep up the good work.

  • Pingback: Renaun Erickson