
Take This One to Work

Figure 1: Factory Method with Single Concrete Creator
You can see the design similarities between this application (MrFace) and the Dragon application. The main difference is that this one has a single concrete factory (FaceCreator) for all of the concrete products. The factory churns out all of the Product children and puts them into an array. The Client requests the array from the Creator and pulls out the elements with a loop. As you can see, they’re all draggable elements. Try out the embedded SWF file below to see how it works:
The same Product (from the Dragon application) is re-used so it is unnecessary to revise it. However, instead of a video and a dynamically generated graphic, all of the graphics were put into the Library as Sprite classes. (To make a Sprite class just change the Base class to flash.display.Sprite.)
The Abstract and Concrete Factories
Because the main difference between this application and the Dragon app is the way in which the factory classes (Creator and FaceCreator) handle products, we’ll start with them. First, the Creator class provides the necessary interface as shown in the following listing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package { //Mr Face App //Asbstract class--serves as interface //Creator import flash.errors.IllegalOperationError; public class Creator { private var dragNow:Array; public function createDragable():Array { dragNow=getDragon(); return dragNow; } // ABSTRACT Method (must be overridden in a subclass) protected function getDragon():Array { throw new IllegalOperationError("Abstract method: must be overridden in a subclass"); return null; } } } |
If you’re thinking, That looks a lot like the Creator class for the Dragon application, you’d be absolutely right. In fact, the only difference is that this Creator returns an Array object instead of a Sprite. That’s the purpose of re-use.
The big change is in the way the ConcreteCreator (FaceCreator) works in this design pattern. The abstract function is getDragon(), and so it has to be overridden and set up to instantiate each of the Product children (facial parts) and stuff them into an array. That array is then returned when requested by the Client.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | package { //Concrete Factory import flash.errors.IllegalOperationError; public class FaceCreator extends Creator { private var faceOn:Array=[]; override protected function getDragon():Array { var ears:Product=new Ears(); faceOn.push(ears); var ears2:Product=new Ears(); faceOn.push(ears2); var glasses:Product=new Glasses(); faceOn.push(glasses); var nose:Product=new Nose(); faceOn.push(nose); var eyes:Product=new Eyes(); faceOn.push(eyes); var mouth:Product=new Mouth(); faceOn.push(mouth); var hair:Product=new Hair(); faceOn.push(hair); var head:Product=new Head(); faceOn.push(head); return faceOn; } } } |
By using an array, the Client only has to request a single object rather than all of the Product children individually as was the case in the Dragon application. That’s it as far as the factory classes are concerned. Next, in looking at the Product and its children classes, you will see that not much has changed from the original designs.
The Product and Its Brood
First of all, take a look at the Product class used as an interface for all of the children classes. Again, the Product is an abstract class instead of an Interface, and it re-uses the same methods and properties.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package { //Abstract class--serves as interface import flash.display.Sprite; import flash.events.MouseEvent; import flash.errors.IllegalOperationError; public class Product extends Sprite { protected var base:Sprite=new Sprite(); // ABSTRACT Method protected function placeParts(lr:uint,ud:uint):void { throw new IllegalOperationError("Abstract method: must be overridden in a subclass"); } protected function setPart(part:Sprite):void { addChild(base); base.addChild(part); base.addEventListener(MouseEvent.MOUSE_DOWN,dragPart); base.addEventListener(MouseEvent.MOUSE_UP,dropPart); } protected function dragPart(e:MouseEvent):void { this.startDrag(); } protected function dropPart(e:MouseEvent):void { this.stopDrag(); } } } |
There’s nothing new from the original in that Product class; so let’s move on to the concrete elements of the Product. The setup for this used Sprite classes stored in the Flash Library. (Creating a similar Library in Flash Builder should not be too difficult.) The setPart() method does most of the work, and the placeParts() method is overridden just to have an abstract method. (That was to demonstrate flexibility more than it was an essential function to override.)
Given that the abstract Product class is a workhorse, the child classes need only to call the Sprite class out of the Library. All Sprite classes end with a capital “S” to differentiate them from the Product subclasses themselves. For example, the Mouth class instantiates a MouthS class from the Library. Each of the face parts is a small subclass, and so all of them are placed together in the following listing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | package { //Concrete Product import flash.display.Sprite; public class Ears extends Product { private var ears:Sprite = new EarS(); public function Ears() { setPart(ears); placeParts(100,100); } override protected function placeParts(lr:uint,ud:uint):void { base.x=lr,base.y=ud; } } } // package { //Concrete Product import flash.display.Sprite; public class Eyes extends Product { private var eyes:Sprite = new EyesS(); public function Eyes() { setPart(eyes); placeParts(100,150); } override protected function placeParts(lr:uint,ud:uint):void { base.x=lr,base.y=ud; } } } // package { //Concrete Product import flash.display.Sprite; public class Glasses extends Product { private var glasses:Sprite = new GlassesS(); public function Glasses() { setPart(glasses); placeParts(80,170); } override protected function placeParts(lr:uint,ud:uint):void { base.x=lr,base.y=ud; } } } // package { //Concrete Product import flash.display.Sprite; public class Hair extends Product { private var hair:Sprite = new HairS(); public function Hair() { setPart(hair); placeParts(100,200); } override protected function placeParts(lr:uint,ud:uint):void { base.x=lr,base.y=ud; } } } // package { //Concrete Product import flash.display.Sprite; public class Head extends Product { private var head:Sprite = new HeadS(); public function Head() { setPart(head); placeParts(120,150); } override protected function placeParts(lr:uint,ud:uint):void { base.x=lr,base.y=ud; } } } // package { //Concrete Product import flash.display.Sprite; public class Mouth extends Product { private var mouth:Sprite = new MouthS(); public function Mouth() { setPart(mouth); placeParts(100,200); } override protected function placeParts(lr:uint,ud:uint):void { base.x=lr,base.y=ud; } } } |
Using Flash Builder (Flex), just place the different graphic elements into separate classes using the same Library class names. Just be sure to subclass them from a Sprite.
The Lazy Client
I’ve come to believe that the less the client has to do, the better. That’s because the Client really should do nothing more than make requests. In some designs the Client is actually part of the design and has more to do. However, as a rule of thumb, the Client should only make requests and place elements on the DisplayList. In this application, that’s all the Client does as you can see in the following listing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package { import flash.display.Sprite; public class Client extends Sprite { private var faceParts:Array=[]; private var myFace:Creator=new FaceCreator(); public function Client() { faceParts=myFace.createDragable(); var saveFace:uint=faceParts.length-1; for (var count:uint =0; count <=saveFace; count++) { addChild(faceParts.pop()); } } } } |
As you can see, the Client just requests the Array from the Creator and then sorts out the array. Now that’s not a lot to do!
Stupid dog tricks: #1 and #2. Just in case you wondered, you can instantiate an array by using aName:Array=[] instead of aName:Array= new Array(). You can do the same thing with an Object using oName:Object={}. Maybe it isn’t as clear as spelling out the object name, but we’re all entitled to a few stupid dog tricks. Those are mine.
Why Take This to Work?
The whole idea behind design patterns is to generate re-usable code that contains good OOP. I realize that a drag-a-face-part game isn’t going to impress your boss (if your boss is infantile, it might) but that’s not important. What is important is to emphasize the fact that as your applications become more complex, you’re either going to have to re-start building applications with every new contract, which will probably include several hacks, make-dos, and god-awfuls. When your customer wants change, it will take time and effort and blow the stuffings out of the current application. So maybe with a simple little face, you can dispel the idea that design patterns will add to a workload. They’re just there to help.
Also, I think that anyone over the age of 5 can do better graphics than I can. So, I’ve provided the entire application including both CS3 and CS4 versions for you to add your own beautiful graphics. (You wonderful graphics folks can send in a fixed-up FLAs with better graphics in the Library, and we’ll gladly add them on the front of this post!). Click the download button to get the whole enchilada:
This is my last post for 2009. See you all next year, and have a great holiday!

The ActionScript 3.0 Design Pattern Re-use and Modification by William B. Sanders, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
Related posts:


Bill Sanders
0 Response to “ActionScript 3.0 Design Pattern Re-use and Modification”