This is one of the few design patterns that I worked up directly from the class diagram and from concepts in GoF. Normally, I like to look at some examples, done in Java or C#, but not this time. As you will see in Figure 1, the pattern appears to be fairly daunting, but I found it to be eminently practical, and it seemed to be a direct response to questions that I had about the Factory Method design pattern (See Chapter 2 for an in-depth explanation of the Factory Method.) You can download the entire example here before continuing if you wish.
Let me start with the gist of the example from GoF and provide something more concrete that’s likely to be a typical kind of issue Flash and Flex developers deal with. Imagine a project where your designers have created general templates for a business site and another for a game site. Their templates include a SWF background and a set of buttons for a UI. The buttons are wholly programmed and require nothing in the Library, and so using them for either Flash or Flex is fairly simple.
You want to keep your design loose, and so you decide that a factory will be helpful. However, clearly you will need a factory to create instances of both buttons and the background template. Further, you want your products to derive from an abstract class to give you as much flexibility as possible. In the example here, you will need an abstract product for buttons and another for backgrounds. You also want your factory abstract enough to make requests for sets of objects from the different products. For example, you want your factory to deliver both a set of buttons and a background that are matching pairs. You don’t want a set of buttons for a game site with a background for a business site, but rather you want the buttons to match your background—business buttons with a business background and game buttons with a game background. This is a job for the Abstract Factory.
Figure 1 shows the class diagram. In looking at the “create” lines (dashed lines), think of them as working with matched sets. The Client requests a business set; and it gets both a business product for buttons and another product for background. So while the diagram may look busy, it really is doing something that makes sense on a basic level. That is, the design is geared to sets; of products with factories that create the requested sets rather than individual objects.

Figure 1: Abstract Factory Class Diagram
Note that Figure 1 shows that both concrete factories create instances from each of the child classes of the two abstract product classes. You can very quickly see the practicality of this when you substitute some concrete elements for the more general conceptual names.
Buttons and Backgrounds
A simple project to use as an example is a program that loads a buttons-background pair. The buttons are made using the SimpleButton class, and the backgrounds are SWF files created using Flash. Figure 2 shows the class diagram for the sample project:

Figure 2: Example of Abstract Factory
The two button classes (RoundBtn and RecBtn) dip into a buttons folder where they pick up the buttons. These other classes not in the diagram can be thought of as helper or utility classes. Likewise, the two SWF files might be considered utility objects in the mix. Figure 3 shows the actual files and folders arranged in the class diagram.

Figure 3: File Diagram of Abstract Factory
No lines go to either the buttons folder or the two .swf files. They’re really not part of the pattern but rather resources (helpers if you wish) for the different participants. If we did add lines, they’d be dashed ones to indicate that the product subclasses create instances of the helpers.
The Client
The Client is a busy object in this design. It holds references not only to the abstract factory (AbFactory) it also holds references to all abstract product classes. The important point here is that by holding references to an interface (the abstract classes), the Client doesn’t get bogged down with specific dependencies. If any of the concrete classes change, the client’s references can handle it. Let’s take a look at the code for this key participant in the pattern:
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 | { import flash.display.Sprite; public class Client extends Sprite { private var busFactory:AbFactory; private var gameFactory:AbFactory; private var btn1:ProductA; private var btn2:ProductA; private var btn3:ProductA; private var gameWall:ProductB; private var busWall:ProductB; private var btnX:int; public function Client() { busFactory=new BusinessFactory(); btnX=20.9; busWall=busFactory.createProductB(); addChild(busWall); btn1=busFactory.createProductA("Accounts"); addChild(btn1); btn1.x=btnX, btn1.y=224; btn2=busFactory.createProductA("Factory"); addChild(btn2); btn2.x=btnX, btn2.y=272; btn3=busFactory.createProductA("Production"); addChild(btn3); btn3.x=btnX, btn3.y=320; //Move block comment symbols to change // from business to game /* gameFactory=new GameFactory(); btnX=18; gameWall=gameFactory.createProductB(); addChild(gameWall); btn1=gameFactory.createProductA("Fire"); addChild(btn1); btn1.x=btnX, btn1.y=224; btn2=gameFactory.createProductA("Move"); addChild(btn2); btn2.x=btnX, btn2.y=272; btn3=gameFactory.createProductA("Hide"); addChild(btn3); btn3.x=btnX, btn3.y=320; // Don’t forget to move close comment block symbol */ } } } |
The first item to note is how the Client class holds references to both the abstract factory and abstract product:
private var busFactory:AbFactory;
private var gameFactory: AbFactory;
…
private var btn1: ProductA;
private var btn2: ProductA;
private var btn3: ProductA;
…
private var gameWall: ProductB;
private var busWall: ProductB;
In this particular example, the choices for a business or game site are separated by commenting out one of the sites. In this case, the business site appears. Of course you can add a UI that would call up one or the other, but this approach seemed a bit clearer. To see one or the other, just change the position of the comment characters (/* and */). So using the default comment characters, when you test the program, Figure 4 shows what you’ll see initially:

Figure 4: Business Site and Buttons
By moving the comment symbols to block out the business options and opening the game options, you’ll see an entirely different background and button set. Figure 5 shows the dramatic difference.

Figure 5: Game Site and Buttons
By comparing Figures 4 and 5, you can see an entirely different set of buttons and background. The square in the middle rotates to further distinguish the game products from the business ones. (I know, gratuitous use of animation. Sorry.)
The Abstract and Concrete Factories
The abstract factory allows far more flexibility than a concrete factory. Because the backgrounds and buttons are clearly different kinds of products, it makes perfect sense to have different kinds of factories to generate the products. The utility of the abstract factory can be seen in the different kinds of concrete factories. As you will see, the concrete factories are only slightly different. Each must create an instance of all products classes (ProductA and ProductB in the example), but because the concrete classes are different they must create different concrete class instances. In this example, The GameFactory and BusinessFactory classes create different buttons and backgrounds and yet each is a child of the abstract factory class. The following listing shows the factory classes:
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 | //Abstract Factory package { import flash.display.Sprite; import flash.errors.IllegalOperationError; public class AbFactory extends Sprite { public function createProductA(txt:String):ProductA { throw new IllegalOperationError("Abstract method: must be overridden in a subclass"); } public function createProductB():ProductB { throw new IllegalOperationError("Abstract method: must be overridden in a subclass"); } } } //Game Factory package { public class GameFactory extends AbFactory { private var gameBtn:ProductA; private var gameWall:ProductB; override public function createProductA(txt:String):ProductA { gameBtn = new RoundBtn(txt); return gameBtn; } override public function createProductB():ProductB { gameWall=new GameStyle(); return gameWall; } } } //Business Factory package { public class BusinessFactory extends AbFactory { private var businessBtn:ProductA; private var businessWall:ProductB; override public function createProductA(txt:String):ProductA { businessBtn = new RecBtn(txt); return businessBtn; } override public function createProductB():ProductB { businessWall=new BusinessStyle(); return businessWall; } } } |
As you can see, each child factory returns its own unique set of buttons and background as shown in Figures 4 and 5 above.
The Abstract Products and their Children
The design pattern shows two abstract products, but you can think of them as at least two products. You can have as many products as you want, but for each abstract product, you need a concrete factory. To help keep everything clear, the abstract product classes were named ProductA and ProductB. The “A” products are buttons and the “B” products are backgrounds. As you can see in the following listings, each is different. Both include abstract methods, but ProductB has a heavily parameterized method, setWallName to add flexibility to the placement of a page header. To help keep everything clear, first you will see the abstract product and then the two concrete children classes for each.
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 142 143 144 145 146 147 148 149 150 151 152 | //Product A: The buttons package { import flash.display.Sprite; import flash.errors.IllegalOperationError; public class ProductA extends Sprite { protected function setUpA(txt:String):void { throw new IllegalOperationError("Abstract method: must be overridden in a subclass"); } } } //Round Button concrete product package { import buttons.BtnStateEllipse; public class RoundBtn extends ProductA { private var btnStateEllipse:BtnStateEllipse; public function RoundBtn(txt:String) { setUpA(txt); } override protected function setUpA(txt:String):void { btnStateEllipse = new BtnStateEllipse(txt); addChild(btnStateEllipse); } } } //Rectangle button concrete product package { import buttons.BtnState; public class RecBtn extends ProductA { private var btnState:BtnState; public function RecBtn(txt:String) { setUpA(txt); } override protected function setUpA(txt:String):void { btnState = new BtnState(txt); addChild(btnState); } } } //Product B: The Backgrounds package { import flash.display.Sprite; import flash.errors.IllegalOperationError; import flash.text.TextField; import flash.text.TextFormat; import flash.text.TextFieldAutoSize; public class ProductB extends Sprite { protected function setWallName(wall:String,sz:int,hor:int,vert:int,txtField:TextField,format:TextFormat):void { txtField.text=wall; txtField.x=hor, txtField.y=vert; txtField.autoSize=TextFieldAutoSize.CENTER; format.size=sz; format.font="Arial Black"; txtField.setTextFormat(format); addChild(txtField); } protected function setUpB():void { throw new IllegalOperationError("Abstract method: must be overridden in a subclass"); } } } //Game Background package { import flash.display.Sprite; import flash.display.Loader; import flash.net.URLRequest; import flash.text.TextField; import flash.text.TextFormat; public class GameStyle extends ProductB { private var loader:Loader; private var url:URLRequest; private var txtField:TextField=new TextField(); private var format:TextFormat=new TextFormat(); public function GameStyle() { setUpB(); setWallName("Game Time!",24,200,30,txtField,format); } override protected function setUpB():void { loader=new Loader(); url=new URLRequest("GameStyle.swf"); loader.load(url); addChild(loader); } } } //Business background package { import flash.display.Sprite; import flash.display.Loader; import flash.net.URLRequest; import flash.text.TextField; import flash.text.TextFormat; public class BusinessStyle extends ProductB { private var loader:Loader; private var url:URLRequest; private var txtField:TextField=new TextField(); private var format:TextFormat=new TextFormat(); public function BusinessStyle() { setUpB(); setWallName("Serious Business",24,200,30,txtField,format); } override protected function setUpB():void { loader=new Loader(); url=new URLRequest("BusinessStyle.swf"); loader.load(url); addChild(loader); } } } |
By requesting the game products, the program returns both the rectangle shape buttons and the game background, and likewise with a request to the business products returns the business set. The separate concrete factories keep everything loose and the pattern has very few dependencies.
The Helpers
The RoundBtn class imports an ellipse button from the buttons package:
import buttons.BtnStateEllipse;
and the RecBtn class imports a rectangle button from the buttons package:
import buttons.BtnState;
So in creating the button scripts, the package indicates the buttons folder. The following scripts are found in the buttons folder. These helper classes are reusable just like the participants in a design pattern. However, because literals are used in these for the colors used with the button states, their flexibility is limited to the particular style and color scheme in the buttons.
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 | //Button style for games package buttons { //Ellipse shape import flash.display.Sprite; import flash.display.Shape; import flash.text.TextFormat; import flash.text.TextField; import flash.text.TextFieldAutoSize; class BtnBaseOval extends Sprite { private var btnLabel:TextField; private var format:TextFormat; private var btnWidth:Number; private var bkground:Shape; public function BtnBaseOval (color:uint,color2:uint,btnLabelText:String) { btnLabel=new TextField(); btnLabel.text=btnLabelText; btnLabel.x=5; btnLabel.textColor=0x24241c btnLabel.autoSize=TextFieldAutoSize.CENTER; format=new TextFormat("Arial Black"); format.size=12; btnLabel.setTextFormat (format); btnWidth=90; bkground=new Shape; bkground.graphics.beginFill (color); bkground.graphics.lineStyle (.25,color2); bkground.graphics.drawEllipse (0,0,btnWidth,18); addChild (bkground); addChild (btnLabel); } } } //Button states and colors game buttons package buttons { import flash.display.SimpleButton; public class BtnStateEllipse extends SimpleButton { public function BtnStateEllipse (txt:String) { upState = new BtnBaseOval(0x698c3a, 0x218894,txt); downState = new BtnBaseOval(0xc7c68d,0x4d0005, txt); overState= new BtnBaseOval(0x48f23,0x218894,txt); hitTestState=upState; } } } //Button style for Business package buttons { //Set up rectangular shape import flash.display.Sprite; import flash.display.Shape; import flash.text.TextFormat; import flash.text.TextField; import flash.text.TextFieldAutoSize; class BtnBaseRec extends Sprite { private var btnLabel:TextField; private var format:TextFormat; private var btnWidth:Number; private var bkground:Shape; public function BtnBaseRec (color:uint,color2:uint,btnLabelText:String) { btnLabel=new TextField() ; btnLabel.text=btnLabelText; btnLabel.x=5; btnLabel.textColor=0x24241c; btnLabel.autoSize=TextFieldAutoSize.LEFT; format=new TextFormat("Verdana"); format.size=12; btnLabel.setTextFormat (format); btnWidth=90; bkground=new Shape; bkground.graphics.beginFill (color); bkground.graphics.lineStyle (.25,color2); bkground.graphics.drawRect (0,0,btnWidth,18); addChild (bkground); addChild (btnLabel); } } } //Button states and colors business buttons package buttons { import flash.display.SimpleButton; public class BtnState extends SimpleButton { public function BtnState (txt:String) { upState = new BtnBaseRec(0xa9b890, 0x24241c,txt); downState = new BtnBaseRec(0xffff7f8,0xcd1722, txt); overState= new BtnBaseRec (0xcd1722,0xa9b890,txt); hitTestState=upState; } } } |
In looking back over this example, keep in mind that these last set of classes, the helper classes, are not part of the pattern itself. Rather, they are used to make it easy to create buttons without resorting to either the button symbols made in Flash or Flex. However, if you’d prefer the factories to use the built-in button components rather than those in the helper classes, you will find it easy to do so. Just change the targets of creation in the concrete product classes where the buttons are assigned.
When to Use the Abstract Factory
The key element in the Abstract Factory Design Pattern is the idea of families of related dependent objects. After working with the pattern for a very short time, it offered up many solutions in my mind. None of us work with single programs—single projects at one time, certainly—but these projects are hardly single programs. They do indeed have certain parts that go together in one context but not another. So instead of having to work up an entire new program to work with families of these objects, this pattern allows you the convenience of working with one group or another depending on the project’s needs.

The ActionScript 3.0 Abstract Factory Design Pattern: Multiple Products and Factories 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
Very cool. The more abstraction, the more flexibility, and also the more reusability. Not only is this good for reusing abstract factories for different style templates, but this can be used in conjunction with an MVC pattern.
For example, if you’re creating a framework where your server returns more than one form of data, say JSON and XML, you could use the abstract factory to create a JSON Model and an XML Model. In addition you could use the abstract factory to create two parsers, one for JSON and one for XML. When you put it all together the controller can determine whether to use JSON or XML and call the relative factory and product, which would then call the proper parser, which could create the proper value objects.
This is a well organized, neatly bundled, clean system that is great for patterns that benefit from modules or components. New components can easily be integrated and require minimal or even no code rewrites.
I’d personally go for one more level of abstraction. There’s little point in importing assets but keeping code in. Often the code will be the biggie, byte-size. I’d preffer to have an open factory interface that the application uses to import SWFs and then create a template.
Hi Nir,
I had not thought of this pattern with the MVC, but I can see your point. However, I did think about the issue of adding more participants. I see two ways to do so. First, you could add more styles–the example has sets for Games and Business. You could add more styles for Social, News, or any other kind of site where you’d need a unique background and set of buttons.
Secondly, you could add more elements to the sets. Instead of having just background and buttons, you could add other elements such as video, images, or any other element that would be common to sites.
Given the abstract character of this design pattern, you have a good deal of flexibility; however, you’d have to keep your eye on organization. I’d really like to see someone add more features or a new set of background and buttons.
Kindest regards,
Bill
Hi Archont,
Thanks for your comments. What you’re suggesting is that you first load the SWF files and then create a template? Correct? In the example, the SWF file is the template. So I’m not sure how you’d first load it and then create a template from it.
I’d like to see more detail about what you have in mind.
Kindest regards,
Bill
Bill,
In response to your question about Archont’s SWF suggestion, you can use SWF’s as a library and pull instances using getDefinitionByName.
Personally, I’d rather use SWFs as the template or component itself, and use SWCs as a utility library.
I hope that’s what Archont meant in regards to his SWF suggestion.
Precisely that. Or to clarify it more for other readers – create such an absract interface that allows one to load any valid template swf, as long as it properly implements the interface/abstract base class it’s being downcast to. Basically making sure you can create a new template swf (for this example it could be MusicStyle, SeamotifStyle or such) and be able to utilize it’s assets without needing to recompile your main application.
While it’s overkill for simple apps it allows other developers, and with the proper component magic, even designers to create custom themes, modules and components without touching the main codebase. Flex for example has Modules, which do this.
Not to mention it makes unit testing easy, compile time short (for the control+enter junkies like me.. and yes, I’ve been compiling everything using Flash so far..) and binary size down to a minimum.
Hi Archont,
Ah…I see. A lot of what we do in this blog is overkill because most of the examples are short enough for readers to digest. Of course, providing an example and the code of what you have in mind would be a treasure!
Cheers,
Bill