Home > Abstract Classes, Abstract Factory, ActionScript, Flash, Flex > ActionScript 3.0 Abstract Factory Design Pattern: Multiple Products and Factories

ActionScript 3.0 Abstract Factory Design Pattern: Multiple Products and Factories

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.

abfactory66

 

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:
abfactoryexample
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.
abfacfile
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:

?View Code ACTIONSCRIPT
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:

 business

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.
game

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:

?View Code ACTIONSCRIPT
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.

?View Code ACTIONSCRIPT
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.

?View Code ACTIONSCRIPT
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.

Share

Related posts:

  1. Runtime Checks for Abstract Classes and Methods in ActionScript 3.0
  2. ActionScript Proxy Design Pattern : The Virtual Proxy (A Minimal Abstract Example)
  3. Abstract is as Abstract Does: A Forrest Gump Approach to Abstract Classes in ActionScript 3.0
  1. January 25, 2009 at 9:14 pm | #1

    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.

  2. January 26, 2009 at 1:21 am | #2

    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.

  3. January 26, 2009 at 1:37 am | #3

    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

  4. January 26, 2009 at 1:42 am | #4

    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

  5. January 26, 2009 at 8:50 am | #5

    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.

  6. January 26, 2009 at 3:07 pm | #6

    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.

  7. January 26, 2009 at 6:39 pm | #7

    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

  8. Alex Winx
    August 4, 2010 at 10:02 am | #8

    I want to point to few things after reading book chapter 2 about Factories
    1.If bussness grow and we bought other printer of same type we will have

    ?View Code ACTIONSCRIPT
    1
    2
    3
    4
    
    var pcHighVol1:PrintCenter = new HighVolPrintCenter( );
    var pcHighVol2:PrintCenter = new HighVolPrintCenter( );
    pcHighVol1.print("Will");
    pcHighVol2.print("Alex");

    so here we lose the meaning of the Factory if we build factory for every product if same machnies could produces lot of type of products :D .
    Instead we might have factory as singleton(extendable one so we might upgrade our factory so it could produce special types of products)

    ?View Code ACTIONSCRIPT
    1
    2
    3
    4
    5
    
    var pcHighVol:PrintCenter = HighVolPrintCenter.getInstance( );<--one factory
    var p1:IPrintJob = pcHighVol.create(WorkgroupPrintjob);<--product1
    var p2:IPrintJob= pcHighVol.create(WorkgroupPrintjob);<---as many products of type WorkgroupPrintjob
    p1.print("Will");
    p2.print("Alex");

    2) Actionscript’s lack of abstract classes and inheritance of Interfaces which would boost Factories for example Interface INewPrintCenter extends IPrintCenter then NewPrintCenter extends INewPrintCenter cos with inheriting of the FactoryClasses we fall in the we dragging but also we should use advantages like undefined number of arguments …args as powerfull
    So

    createPrintjob( );
    createPrintjob(cKind:uint);

    might become

    createPrintjob(...args );

    So Factory creator method is more useful and escape creating new Factory just cos of different constructors params of the family object as much as we could.

    3) As Factory is good for family and family most of the time is more then 2 products …
    so if/then and even switch (is this not design pattern too? on the low level :) )) like this

    ?View Code ACTIONSCRIPT
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    if (cKind == BW)
    {
    trace("Creating new printjob for the b/w inkjet printer");
    return new InkjetPrintjob( );
    } else if (cKind == COLOR) {
    trace("Creating new printjob for the color inkjet printer");
    return new ColorInkjetPrintjob( );
    } else {
    throw new Error("Invalid low volume print job");
    return null;
    }

    decrease the power/speed/extensibility of production of the Factory
    so we might use
    A.event/delegate system

    addListener(BW,fObjectCreator);
    dispatch(new Event(BW,args)

    B.signals
    C.or at least map (Vector,Array,Dictionary) key/values

    [BW]=new InkjetPrintjob( );
    or [BW]=fObjectCreator
    where key is switch code of what kind of family object we wont to create and value is constructor or
    function creator
    So in
    function createPrintjob(...args):IPrintJob
    {
    return [BW];
    return [BW].apply(InkjetPrintjob,args);<--better
    }

    this way can even extend the fucntionality of the Factory(Factory could produce now diffrent type products) during run-time. Let say we inject USB so now printer can print 4MB pages instead of 2MB
    before and this is special case and you don't need to build new Factory (extending the basic one)

    Factory.add("MY",myPrintJobFunction)
    {
    [MY]=myPrintJobFunction;
    }

    4) So inheritance not always mean (http://www.as3dp.com/2009/02/21/design-pattern-principles-for-actionscript-30-favor-object-composition-over-class-inheritance/) when you sure that at least 90% of your object would use that functionality. For example all printers would have memory and paperfeeder but have different print() functionality.
    Should I put in every Printjob that implements IPrintJob, memory and paperfeeder. Lot of waste.

    Putting memory,paperfeeder in class PrintJob would be great cos every printer that extend would have thoose(at least most of products would have it). But puting print() in PringJob class would be just oveloading cos every extended PrintJob class would implement by itself no matter what. So print() should stay in IPrintJob.

    InkjetPrintjob extends PrintJob implements IPrintJob might be good solution taking the goods from both worlds.
    King Regards
    Alex

  9. August 4, 2010 at 2:28 pm | #9

    Hi Alex,

    Some interesting comments there, and even though your comments seem to be for Chapter 2 (written by Chandima), let me make a few comments regarding factories.

    1. While it is true that ActionScript has no abstract classes, it is not too difficult to treat classes as such and override the functions (methods) to effectively do what abstract classes do. See pp 68-69 in Ch 2.

    2. You are right in pointing out that you cannot inherit an Interface, you implement them and in doing so you “get” the template by implementing concrete instances of the methods in the interface. By programming to the interface, you can have loose coupling, making it easy to add new concrete participants or change existing ones.

    3. I’m not sure you meant this, but did you say (ask) if the switch statement is a design pattern? No, it is not. It is a statement for dealing with multiple conditionals.

    As for the general task of adding another factory, I think that you’re actually talking about adding another concrete Product and a Concrete Creator to instantiate it. Take a look at the post we have on lazy initialization and the ConcreteProduct/ConcreteFactory relationship.

    Thanks for your comments,
    Bill

  10. Alex Winx
    August 4, 2010 at 3:51 pm | #10

    Hi Bill
    I’m really,really sorry that my post was pipe out to totally in different direction meant to be and would like to thx about teaching points of using Interface,switch statement and abstract class…
    .
    In Lazy Initialization I would personally use one Factory/Creator/Maker of whatever for creating shapes but you guys are reach so you would build 3 factory for each product :) ).

    Maybe source would show the point better.

    ?View Code ACTIONSCRIPT
    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
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    
    package winxalex.fuzzy
    {
     
    	/**
    	 * ...
    	 * @author alex winx
    	 */
    	public interface IFuzzyMembershipFunctionFactory
    	{
     
     
    		 function create(funcType:uint,...args):IFuzzyMembershipFunction
     
    	}
     
    }
     
     
     
     
    package winxalex.fuzzy
    {
    	import flash.events.EventDispatcher;
    	import flash.utils.Dictionary;
    	import flash.utils.getQualifiedClassName;
        import flash.utils.getQualifiedSuperclassName;
     
     
    	/**
    	 * ...
    	 * @author alex winx
    	 */
    	public class FuzzyMembershipFunctionFactory implements IFuzzyMembershipFunctionFactory
    	{
    		//private static var product:IFuzzyMembershipFunction;
    		//private static var dispatcher:EventDispatcher = new EventDispatcher();
    	     private static var _instance:FuzzyMembershipFunctionFactory = new FuzzyMembershipFunctionFactory();
             private static var _className:String = getQualifiedClassName(super);
     
    		private static var funcDictionary:Vector. = FuzzyMembershipFunctionFactory.init();
     
    		public function FuzzyMembershipFunctionFactory():void
    		{
    			if (_instance != null &amp;&amp; getQualifiedSuperclassName(this) != _className) throw new Error("Factory is Singleton. Use FuzzyMembershipFunctionFactory.getInstance()");
    		}
     
    		public function create(funcType:uint,...args):IFuzzyMembershipFunction
    		{
    			//version 1 dispatcher.dispatchEvent(new MembershipFunctionCreateEvent(funcType,afgs...)
    			//version 2 using signal
     
    			//version 3
    			return funcDictionary[funcType].apply(FuzzyMembershipFunctionFactory, args);
    		}
     
    		public static function getInstance():FuzzyMembershipFunctionFactory
    		{
    			return _instance;
    		}
     
    		private static function createTriangleFunction(...args):IFuzzyMembershipFunction
    		{
    			return new FuzzyTriangleMembershipFunction(args[0], args[1], args[2], args[3]);
    		}
     
     
     
    		private static function init():Vector.
    		{
    			var vect:Vector. = new Vector.;
    			vect[FuzzyMembershipFunction.TRIANGLE] = createTriangleFunction;
    			vect[FuzzyMembershipFunction.LEFT_SHOULDER] = createTriangleFunction;
    			vect[FuzzyMembershipFunction.RIGHT_SHOULDER] = createTriangleFunction;
    			return vect;
    		}
     
    		public static function add(name:String,funct:Function):void
    		{
    			funcDictionary[name] = funct;
    		}
    	}
     
    }
     
     
     
     
    package winxalex.fuzzy
    {
     
    	/**
    	 * ...
    	 * @author alex winx
    	 */
    	public interface IFuzzyMembershipFunction
    	{
     
     
    		function calculateDOM(value:Number):void
     
     
    	 function toString():String;
     
     
     
    	}
     
    }
     
     
    package winxalex.fuzzy
    {
    	/**
    	 * ...
    	 * @author alex winx
    	 */
    	public class FuzzyMembershipFunction
    	{
    		public static const TRIANGLE:uint = 0;
    		public static const LEFT_SHOULDER:uint = 1;
    		public static const RIGHT_SHOULDER:uint = 2;
    		public static const TRAPEZOID:uint = 3;
    		public static const QUADRIC:uint = 4;
    		public static const SQUARE:uint = 5;
    		private var _degreeOfMembership:Number = 0.0;
    		public var linguisticQuantifier:String;
    		public var   peakPoint:Number;
    		public var  leftOffset:Number;
            public var rightOffset:Number;
     
    		public function FuzzyMembershipFunction(linguisticQuantifier:String,peakPoint:Number=NaN,leftOffset:Number=NaN,rightOffset:Number=NaN,...args) :void
    		{
    			this.linguisticQuantifier = linguisticQuantifier;
    			this.peakPoint = peakPoint;
    			this.rightOffset = rightOffset;
    			this.leftOffset = leftOffset;
    		}
     
    		public function get degreeOfMembership():Number { return _degreeOfMembership; }
     
    		public function set degreeOfMembership(value:Number):void
    		{
    			_degreeOfMembership = value;
    		}
     
     
    		public function toString():String
    		{
     
    			var s:String = "linguisticQuantifier=" + linguisticQuantifier + " DOM:"+_degreeOfMembership+  " peakPoint =" + peakPoint + "rightOffset=" + rightOffset +"leftOffset=" + leftOffset;
    			return  s;
    		}
     
    	}
     
    }
     
     
    package winxalex.fuzzy
    {
    	import winxalex.fuzzy.FuzzyMembershipFunction;
    	/**
    	 * ...
    	 * @author alex winx
    	 */
    	public class FuzzyTriangleMembershipFunction extends FuzzyMembershipFunction implements  IFuzzyMembershipFunction //extends FuzzyMembershipFunction
    	{
     
    		/*public function FuzzyTrianlgeMembershipFunction()
    		{
     
    		}*/
     
    		/*public function getFunction(linguisticQuantifier:String, peakPoint:Number = NaN, leftOffset:Number = NaN, rightOffset:Number = NaN):IFuzzyMembershipFunction
    		{
    			//return new FuzzyMembershipFunction(linguisticQuantifier, peakPoint, leftOffset, rightOffset);
    			return super(linguisticQuantifier, peakPoint, leftOffset, rightOffset);
    		}*/
     
    		public function FuzzyTriangleMembershipFunction(linguisticQuantifier:String,peakPoint:Number=NaN,leftOffset:Number=NaN,rightOffset:Number=NaN) :void
    		{
    			super(linguisticQuantifier, peakPoint, leftOffset, rightOffset);
    		}
     
    		public function calculateDOM(value:Number):void
    		{
    			    var grad:Number;
     
     
    					  //test for the case where the triangle's left or right offsets are zero
    					  //(to prevent divide by zero errors below)
    					  if ( (rightOffset==0 &amp;&amp; peakPoint, value) || ( leftOffset==0.0 &amp;&amp; peakPoint==value))
    					  {
    							degreeOfMembership= 1.0;
    					  }
     
    					  //find DOM if left of center
    					  if ( (value = (peakPoint - leftOffset)) )
    					  {
    						  grad = 1.0 / leftOffset;
     
    						degreeOfMembership= grad * (value - (peakPoint - leftOffset));
    					  }
     
    					  //find DOM if right of center
    					  else if ( (value &gt; peakPoint) &amp;&amp; (value &lt; (peakPoint + rightOffset)) )
    					  {
    						grad = 1.0 / -rightOffset;
     
    						degreeOfMembership= grad * (value - peakPoint) + 1.0;
    					  }
     
    					  //out of range of this FLV, degreeOfMembership= zero
    					  else
    					  {
    						degreeOfMembership= 0.0;
    					  }
     
    		}
     
    	}
     
    }
     
    var factory:IFuzzyMembershipFunctionFactory = FuzzyMembershipFunctionFactory.getInstance();
    			var func:IFuzzyMembershipFunction=factory.create(FuzzyMembershipFunction.TRIANGLE,&quot;bla&quot;, 230, 120, 320);
    • May 30, 2011 at 1:49 am | #11

      Hey Alex,

      I’m sorry it took me so long to get back to you, but when I first looked at your code and comment, I wasn’t sure what point you were trying to make. If you were attempting to show that you could do the same thing with fewer classes or less code; that’s always possible with design patterns. However, the point is never to write compact code with a pattern; but rather to write code that is easy to reuse and add to or change.

      Why you put a Singleton in the factory is equally unclear, but maybe you have a good reason that I missed. For a lot of reasons that have been discussed on this blog, I avoid Singletons, and even if you were using a non-DP singleton, you may have created tighter binding, which is not a good thing.

      In any case it looks like you put a lot of thought into your example, and I’d like very much to know what exactly you were attempting to accomplish. It looks very interesting.

      Kindest regards,
      Bill

  11. Amy
    May 29, 2011 at 6:21 pm | #12

    If you hit this page with the debug player, you get “TypeError: Error #1010: A term is undefined and has no properties.
    at socialmedia2010v2_160x600_fla::MainTimeline/setChallengeFields()
    at socialmedia2010v2_160x600_fla::MainTimeline/decodeChallenge()
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at flash.net::URLLoader/onComplete()”

    This crashes IE8. I don’t think it is your example factory code–I think it is the O’reilly Giving page ad.

    Since your audience is more likely than most to have the debug player, you may want to consider fixing this.

    HTH;

    Amy

    • May 30, 2011 at 1:34 am | #13

      Hi Amy,

      That is an important issue. Chandima is in charge of keeping our blog in one piece, and I will pass this on to him.

      What I’m curious about is why IE8 would crash due to the O’Reilly ad. Have you noticed any similar problems with any of the design patterns or examples we’ve provided?

      Kindest regards,
      Bill

  12. Daniel
    August 14, 2011 at 6:24 pm | #14

    I have a question.

    on:

    btn1 = busFactory.createProductA(“Accounts”);

    Why not first

    btn1 = new ProductA();
    btn1 = busFactory.createProductA(“Accounts”);

    ?

    Thanks.

  13. August 14, 2011 at 7:09 pm | #15

    Hi Daniel,

    The purpose of any Factory design is to unlink (or create a loose link) between the product and the request for the product. By using a factory, another class makes that request through an interface. It accomplishes the same thing, but with the ability to keep the linkage flexible.

    Remember the first principle of design patterns is to Program to the interface and not the implementation. Since ProductA is an implementation by declaring it directly (btn1=new Product()), you’re still programming to the implementation.

    However, you have to ask the question that you did to really understand design patterns.

    Kindest regards,
    Bill

  1. January 30, 2009 at 2:14 pm | #1
  2. November 27, 2010 at 1:20 pm | #2
  3. March 16, 2011 at 9:25 pm | #3

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>