By paddloPayday loans

Home > Factory Method, Lazy Initialization, Lazy instantiation > The Button Factory: Labels and Buttons from the Same Factory Methods

The Button Factory: Labels and Buttons from the Same Factory Methods

A UI Factory for Buttons and Labels

Beginning of a UI Factory

The other day I was looking at an ActionScript 3.0 program, and the developer used a ‘UI Factory.’ I looked at it, and while the program did indeed get UIs from the UIFactory class, it wasn’t a design pattern. Instead the UI Factory was just a single class with a bunch of methods for building different parts of a UI. Included in the factory, though, was a call to another class that also was part of the overall UI.

Basically, the call from one factory product to another made the requesting product a client. So, I thought, why not create a factory method design pattern where one part of a product called another to complete the product? The design pattern would be a straightforward Factory Method pattern, and the call from within the pattern would follow the same call through the Creator as a call from a general Client class would be. In this way, I would be able to use the same interfaces (abstract classes) for calls within the pattern as well as from outside the pattern by an external Client class.

A Button and Label Factory

The basic process is the same used in the post describing Lazy Initialization on this blog. The difference is that one product uses another product in the factory process. To get started, take a look at Figure 1 that shows how an external client and the UIButton both make requests through the UICreator. The external client can get either a button or just the label, but when a button is requested, it then requests a label to go with it.

uifact

Figure 1: Request by button and external client for a label

The button uses a Sprite object for the base of a graphic gradient shape using a round rectangle. The label is put into a Sprite as well and then added to the button. The Sprite is inherited from the same UIProduct class.

Creators and Products

Just like any other Factory Method, the pattern uses abstract classes for both the UICreator and the UIProduct. The following listing shows that both abstract classes have methods that use the same set of parameters.

?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
//Creator
package 
{
	import flash.display.Sprite;
	import flash.errors.IllegalOperationError;
	// ABSTRACT Class (should be subclassed and not instantiated)
	public class UICreator
	{
		protected var product:UIProduct;
 
		// ABSTRACT Method (must be overridden in a subclass)
		public function factoryMethod(msg:String,hor:Number,v:Number,col:uint,w:Number,h:Number):Sprite
		{
			throw new IllegalOperationError("Abstract method: must be overridden in a subclass");
			return null;
		}
	}
}
 
//Product
package 
{
	import flash.display.Sprite;
	import flash.errors.IllegalOperationError;
 
	// ABSTRACT Class (should be subclassed and not instantiated)
	class UIProduct
	{
		protected var ui:Sprite;
 
		public function getUI(msg:String,hor:Number,v:Number,col:uint,w:Number,h:Number):Sprite
		{
			throw new IllegalOperationError("Abstract method: must be overridden in a subclass");
			return null;
		}
	}
}

The “abstracting” of the classes provides a good deal of flexibility and bindings are loose. The concrete implementations are only two of a larger planned UI set. However, it’s not difficult to add any concrete UI you want.

The Concrete Label Maker and Product

First, take a look at the concrete label and label creator. The creator uses lazy initialization, and the concrete label product uses TextField and TextFormat objects for the label product.

?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
//Concrete Label Creator
package 
{
	import flash.display.Sprite;
	public class SpriteLabelMaker extends UICreator
	{
		public override function factoryMethod(msg:String,hor:Number,v:Number,col:uint,w:Number,h:Number):Sprite
		{
			if (! product)
			{
				product=new SpriteLabel();
			}
			return product.getUI(msg,hor,v,col,w,h);
		}
	}
}
 
//Concrete Label Product
package 
{
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFieldAutoSize;
	import flash.display.Sprite;
 
	public class SpriteLabel extends UIProduct
	{
		private var txtLabel:TextField;
		private var txtFormat:TextFormat;
 
		public override function getUI(msg:String,align:Number,v:Number,col:uint,w:Number,h:Number):Sprite
		{
			ui=new Sprite();
			txtFormat=new TextFormat();
			txtFormat.font="Arial Black";
			txtFormat.color=0xffffff;
			txtLabel = new TextField();
			txtLabel.defaultTextFormat = txtFormat;
			txtLabel.text = msg;
			txtLabel.autoSize = TextFieldAutoSize.LEFT;
			txtLabel.selectable = false;
			txtLabel.x = align / 2;
			txtLabel.y = h/4;
			ui.addChild(txtLabel);
			return ui;
		}
	}
}

By including both TextField and TextFormat objects, the look and feel of the button labels have a good deal of flexibility. Currently set to create only white buttons, the color parameter (col) could be used to add more appropriate colors if needed.

The Concrete Button Maker and Product

Like the label, the concrete implementations of the creator and product abstract classes use the same set of method parameters. However, the button product acts as a client calling for a label product through the UICreator interface (abstract class). Both return a Sprite object, but when the button object appears, it always has a label with it. So a request for a button object is also a request for a label object. Labels, however, may be requested by a client without having to get a button object as well.

?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
//Button concrete Creator
package 
{
	import flash.display.Sprite;
	public class SpriteButtonMaker extends UICreator
	{
		public override function factoryMethod(msg:String,hor:Number,v:Number,col:uint,w:Number,h:Number):Sprite
		{
			if (! product)
			{
				product=new SpriteButton();
			}
			return product.getUI(msg,hor,v,col,w,h);
		}
	}
}
 
//Button concrete Product
package 
{
	import flash.display.Sprite;
	import flash.display.GradientType;
	import flash.display.SpreadMethod;
 
	public class SpriteButton extends UIProduct
	{
		private var lbl:UICreator;
		public override function getUI(msg:String,hor:Number,v:Number,col:uint,w:Number,h:Number):Sprite
		{
			ui= new Sprite();
			var fill:String = GradientType.LINEAR;
			var spread:String = SpreadMethod.PAD;
			ui.graphics.beginGradientFill(fill, [col, 0x70c656],[1,1],[127,255],null,spread,"rgb",0);
			//Button shape (x,y,width, height, corner)
			ui.graphics.drawRoundRect(0,0,w, h, 8, 8);
			ui.graphics.endFill();
			ui.x=hor, ui.y=v;
			ui.buttonMode = true;
			ui.useHandCursor = true;
			lbl=new SpriteLabelMaker();
			ui.addChild(lbl.factoryMethod(msg,hor,v,col,w,h));
			return ui;
		}
	}
}

Both the graphic portion and label portion of the button use the ui property inherited and implemented from the UIProperty class. In that respect the button product is recursively formed. It is built by embedding the label Sprite into the button Sprite.

Finally, here’s an example of a Client. It creates two different buttons based on the arguments.

?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
package 
{
	import flash.display.Sprite;
 
	public class UIClient extends Sprite
	{
		private var btnMk:UICreator;
		private var lbl:UICreator;
		private var btn:Sprite=new Sprite;
		private var btn2:Sprite=new Sprite;
 
		public function UIClient()
		{
			btnMk=new SpriteButtonMaker();
			//(for label,x,y,color,width,height)
			btn=btnMk.factoryMethod("Click Here",40,40,0x53933f,120,50);
			addChild(btn);
			btn2=btnMk.factoryMethod("Magic",40,110,0x0000cc,100,32);
			addChild(btn2);
		}
	}
}

Figure 2: Flexibility in Button Factory

The buttons created have some range, and by adding more parameters, you can extend that range to a wider variety of gradient colors and different fonts and font sizes. However, for now, you can see how the buttons can be created using a simple Factory Method. Here’s a great opportunity to show off some different examples and tweaks to make the pattern more flexible for your needs.

One important feature I tested with this little design pattern was whether the buttons could indeed be used as buttons. Most importantly, I wanted to make sure that they could handle event listeners that in turn could handle events. Fortunately, they worked like any other button, and all that was necessary was to make sure that the buttonMode and useHandCursor properties were set to true. I have a feeling that this is a little application that I’ll be re-using a lot and tweaking a lot more!

Share

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>