Today I found yet another good reason to test PixLib (and I still have some others in mind that are to come, like removing all my dependencies on the mx.* packages)
To give a bit of background, the application im building is a drag-and-drop based story creator for schoolkids. Theres a stage onto which they can add different types of things (aka artifacts) and move them around, scale, rotate etc.. Now most artifacts behave the same way, but some need special abilities, for example speech bubbles have text which can be edited ‘live’ (i.e. inside the bubble not in a seperate text field) and there are other types of artifact with their own peculiarities. Each of these types of artifact inherits from one base class and its this base class which most of the application deals with. It doesnt need to know about the difference between a normal artifact and a speech bubble it just wants to keep a list of them, save and restore their state etc..
To attain this goal i have decided to use a factory to create the artifacts. A factory is just a class (or often a single method) that is used to create objects. If you havent heard of these then Wikipedia has some more information: Factory Method Pattern and Abstract Factory
At creation time I know the type of the artifact I want (its a string property of an Artifact model object) and I need to create the corresponding UI object. I could code my own factory method or factory class and use a big if / else (or switch / case) construct to decide what to build depending on the artifact type but there has to be a better way. Enter PixLib’s AbstractFactory.
If you look at the API for AbstractFactory its very minimal, the only public method is push (sKey:String, classConstructor:Function). This is used to register the types of objects I want to build.
Now if you look at the source you will notice the more interesting method _buildInstance (much like the buildInstance from the HashCodeFactory from the previous post).
Because its an AbstractFactory that means I have to make my own concrete subclass which will implement my factory method. I also need to register the types I want to create by their string identifiers.
(Its worth noting at this point that the PixLib AbstractFactory class doesnt play the exact role of the AbstractFactory class in the canonical AbstractFactory Pattern. It is ‘Abstract’ because you create concrete subclasses and dont use it directly but unlike the usual AbstractFactory in the pattern it doesnt have the same interface as those subclasses, instead it provides a facility for dynamically linking identifiers to class constructors which the concrete subclasses can use to create objects.
If thats just made things even more confusing dont worry about it..)
First, I need to extend the Abstract Factory and register my types :
class EditableObjectFactory extends AbstractFactory
{
// private constructor for Singleton
private function EditableObjectFactory()
{
super();
// register artifact types
push(Character.TYPE_ID,Character);
push(SpeechBubble.TYPE_ID,SpeechBubble);
}
...
}
Then I can implement my factory method which looks a bit like this :
public function createEditableObject(artifact:ArtifactModel,mc:MovieClip):EditableObject
{
// Create instance according to artifact type (i.e. Character.TYPE_ID, SpeechBubble.TYPE_ID etc..)
return _buildInstance(artifact.getType(),mc);
}
Then the application code can just ask the EditableObjectFactory to create the appropriate item when a user requests a new artifact to be added to the stage.
Another benefit of this is that each of the 3 versions of the application can easily add their own custom artifact types. They each just register the type with EditableObjectFactory at startup and the rest happens like magic. 🙂
Another examples is available within PixLib. If you look at the TweenFactory class in the com.bourre.transitions package you will see that it subclasses AbstractFactory to be able to create instances of Tween objects.
If you find yourself in the situation where you are dealing with a set of if / else or switch / case statements when you are creating objects then its definitely worth considering using a factory and encapsulating the creational process into its own class.
Nice tut, thanks again for sharing.
You’re right when you say AbstractFactory is not an implementation of abstract factory pattern, it’s called abstract coz that’s an abstract class. 😉
Really great article. Please, keep ’em coming, Martin!
Martin, great post here. Can you shoot me an email (I couldn’t find your email anywhere here), I’d like to talk to you about something you mentioned in here. I have a project that you might be interested in working on.