The ActionScript 3.0 Flyweight Saga: Part III Aggregation Aggravation, Stuff on the Stage and the Intrinsic State

Aggregation Aggravation

In the first installment of this Flyweight Saga, I noted that the relationship between a Flyweight and Flyweight Factory class is one of aggregation. The initial example shows that the Retrieve method in the Factory class returns an instance of IFlyweight, meeting the requirement of the proper connection between the two classes. In looking at one example in Java, (even with modest Java skills), the program clearly did not have such a relationship between the Factory and Flyweight. In fact, it claimed, that an object’s extrinsic state can be shared by classes. Now, maybe that was unfortunate wording because the big feature of the Flyweight design pattern is that the Flyweight can be a shared object, but only the intrinsic state can be shared. (Maybe the author meant that extrinsic states can be shared between classes in a Flyweight design pattern, and that’s probably right but is not a key feature of the pattern.)

Anyway, after looking at several different descriptions of aggregation, including the one provided by the GoF, it’s clear that the concept is one with fuzzy borders and can slip into either general composition or acquaintance. It implies that the Flyweight Factory aggregates the Flyweight—no Flyweight, no Factory. As a result, the life of the aggregator (Flyweight Factory) depends on the life of the aggregatee (Flyweight). Like acquaintance, aggregation is implemented with references or pointers rather than defining variables of once class in another. (Apparently C++ is an exception and does set up aggregation by defining variables from the aggregatee class.)

By and large the issue has not been especially significant so far because all of the output was using trace statements, and so output was largely confined to built-in features that only work when the code is run in test mode. It’s great for debugging up to a point, but developing with trace statements that do not take into account how certain graphic elements, especially those that are accessed by extending the Sprite classes, can generate unusable structures for applications that employ graphics and other elements that require the import and extension of other classes. In this next Flyweight example, we leave the realm of trace and use the graphics property (from the Sprite class) to draw solid balls using fill methods. The ball class extends Sprite and implements the interface. That’s all fine and good, but the aggregation becomes problematic in even the simplest example. In taking the general structure from the examples examined up to this point (Parts I and II of the Flyweight Saga), we can begin to see the trouble.

Because of the need to introduce the Sprite reference somewhere in the Flyweight by extending the Sprite class the Flyweight had to be referenced indirectly through the Concrete Flyweight (FlyBall). Does this count? I don’t know, but using an interface instead of an abstract class, I could see no way in getting in the needed Sprite extension. However, I do think that the Flyweight Factory did accomplish the manufacture of a single instance with multiple copies of an object with both the red and yellow balls. The following code is the first go at this using something other than trace. However, is it indeed a true Flyweight design 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
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
package 
{
	//Flyweight
 
	public interface IFlyweightBall
	{
		function doCircle (xPos:uint,yPos:uint,radius:uint):void;
	}
}
 
package 
{
	//Flyweight Factory
 
	public class BallFactory
	{
		protected var ballIntrinsic:Object={};
 
		public function BallFactory ()
		{
			ballIntrinsic["red"]=new FlyBall(0x990000);
			ballIntrinsic["yellow"]=new FlyBall(0xffff00);
 
		}
		public function getIntrinsic (key:String,... rest):FlyBall
		{
			switch (ballIntrinsic[key] != undefined)
			{
				case true :
					break;
				case false :
					ballIntrinsic[key]=rest[0];
					break;
			}
			return ballIntrinsic[key];
		}
	}
}
 
package 
{
	//Concrete Flyweight
 
	import flash.display.Sprite;
 
	public class FlyBall extends Sprite implements IFlyweightBall
	{
		protected var fill: uint;
 
		public function FlyBall (fill:uint)
		{
			this.fill=fill;
		}
 
		public function doCircle (xPos:uint,yPos:uint,radius:uint):void
		{
			graphics.beginFill (fill);
			graphics.drawCircle (xPos,yPos,radius);
			graphics.endFill ();
		}
	}
}
 
package 
{
	//Client class
	import flash.display.Sprite;
 
	public class BallClient extends Sprite
	{
 
		//Client data to provide extrinsic state details
		private var xPos;
		private var yPos;
		private var radius;
 
		public function BallClient ()
		{
			var ballFactory:BallFactory=new BallFactory;
 
			var cir1:FlyBall=ballFactory.getIntrinsic("red");
			shuffle ();
			cir1.doCircle (xPos,yPos,radius);
			addChild (cir1);
 
			var cir2:FlyBall=ballFactory.getIntrinsic("red");
			shuffle ();
			cir2.doCircle (xPos,yPos,radius);
			addChild (cir2);
 
			var cir3:FlyBall=ballFactory.getIntrinsic("yellow");
			shuffle ();
			cir3.doCircle (xPos,yPos,radius);
			addChild (cir3);
 
			var cir4:FlyBall=ballFactory.getIntrinsic("yellow");
			shuffle ();
			cir4.doCircle (xPos,yPos,radius);
			addChild (cir4);
 
			//Constructed in client
			var cir5:FlyBall=ballFactory.getIntrinsic("green",new FlyBall(0x009900));
			shuffle ();
			cir5.doCircle (xPos,yPos,radius);
			addChild (cir5);
		}
 
		private function shuffle ()
		{
			//Generate extrinsic states
			xPos=Math.round(Math.random() * 500);
			yPos=Math.round(Math.random() * 300);
			radius=Math.round(Math.random() * 100);
		}
	}
}

When this application is tested, you will see two red balls, two yellow balls and a green ball seen in Figure 1. The following line in the Flyweight Factory,

public function getIntrinsic (key:String,... rest):FlyBall

sets up the returned data as a concrete flyweight (FlyBall). In looking at the UML diagram for the Flyweight (See Part I of the Flyweight saga), the Flyweight Factory is an aggregation of the Flyweight. The aggregation relationship is one where the aggregator (Flyweight Factory) holds a reference to the aggregatee (Flyweight), but as you can see, the reference is to the Concrete Flyweight.

Figure 1

Abstract Class Changes Everything

The first ActionScript 3.0 Flyweight I worked was the one Jim Kremens had made for test of concept. It employed an abstract class rather than an interface, and I changed it to an interface. Now, I’ve come full circle back to the abstract class because it can be set up to inherit the needed elements of the Sprite class. This allows the Factory to establish a reference to the Flyweight rather than having to use a concrete Flyweight. The resulting application now has all of the right relationships.

?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
package 
{
	//Abstract class Flyweight
	import flash.display.Sprite;
 
	public class FlyweightBall extends Sprite
	{	
			function doCircle (xPos:uint,yPos:uint,radius:uint):void
			{}
	}
}
 
package 
{
	//Flyweight Factory
 
	public class BallFactory
	{
		protected var ballIntrinsic:Object={};
 
		public function BallFactory ()
		{
			ballIntrinsic["red"]=new FlyBall(0x990000);
			ballIntrinsic["yellow"]=new FlyBall(0xffff00);
 
		}
		public function getIntrinsic (key:String,... rest):FlyweightBall
		{
			switch (ballIntrinsic[key] != undefined)
			{
				case true :
					break;
				case false :
					ballIntrinsic[key]=rest[0];
					break;
			}
			return ballIntrinsic[key];
		}
	}
}
 
package 
{
	//Concrete Flyweight
 
	public class FlyBall extends FlyweightBall
	{
		private var fill: uint;
 
		public function FlyBall (fill:uint)
		{
			this.fill=fill;
		}
 
		override function doCircle (xPos:uint,yPos:uint,radius:uint):void
		{
			graphics.beginFill (fill);
			graphics.drawCircle (xPos,yPos,radius);
			graphics.endFill ();
		}
	}
}
 
package 
{
	//Client class
	import flash.display.Sprite;
 
	public class BallClient extends Sprite
	{
 
		//Client data to provide extrinsic state details
		private var xPos;
		private var yPos;
		private var radius;
 
		public function BallClient ()
		{
			var ballFactory:BallFactory=new BallFactory;
 
			var cir1:FlyweightBall=ballFactory.getIntrinsic("red");
			shuffle ();
			cir1.doCircle (xPos,yPos,radius);
			addChild (cir1);
 
			var cir2:FlyweightBall=ballFactory.getIntrinsic("red");
			shuffle ();
			cir2.doCircle (xPos,yPos,radius);
			addChild (cir2);
 
			var cir3:FlyweightBall=ballFactory.getIntrinsic("yellow");
			shuffle ();
			cir3.doCircle (xPos,yPos,radius);
			addChild (cir3);
 
			var cir4:FlyweightBall=ballFactory.getIntrinsic("yellow");
			shuffle ();
			cir4.doCircle (xPos,yPos,radius);
			addChild (cir4);
 
			//Constructed in client
			var cir5:FlyweightBall=ballFactory.getIntrinsic("green",new FlyBall(0x009900));
			shuffle ();
			cir5.doCircle (xPos,yPos,radius);
			addChild (cir5);
		}
 
		private function shuffle ()
		{
			//Generate extrinsic states
			xPos=Math.round(Math.random() * 500);
			yPos=Math.round(Math.random() * 300);
			radius=Math.round(Math.random() * 100);
		}
	}
}

The Intrinsic State

Part II of the Flyweight Saga examined extrinsic states, which are part of the key operation in the Flyweight. However, it is the intrinsic state in the concrete flyweight where we need to look now. In looking at the UML diagram, the intrinsic state is stored in the Concrete Flyweight. So, while extending the Flyweight and implementing the key operation, we need to add an intrinsic state. In this case, the intrinsic case is placed as a parameter within the concrete flyweight constructor. The following lines are the crux of the intrinsic state:

protected var fill: uint;
public function FlyBall (fill:uint)
{
this.fill=fill;
}

The protected variable fill is the key here. As part of the constructor, the fill value is stored in the concrete flyweight. Then, when the operation calls the extrinsic parameters, the fill variable provides the color code for the concrete flyweight’s implementation of the instance. So, once the ball instance is created in the factory participant (BallFactory), the intrinsic value remains constant no matter what the values of the extrinsic values passed in the concrete flyweight method. As a result, it is possible to make multiple instances of the red and yellow balls using the intrinsic color that was in the associative array (ballIntrinsic). Thus, the line,

ballIntrinsic["red"]=new FlyBall(0x990000);

creates a “red” instance providing the fill color value in the construction parameter (0x990000). If the same key is called from the client, the getIntrinsic function checks to see if it exists or not. If it does, it simply returns the instance with the included color value stored as an intrinsic state. The extrinsic states, which include the radius, and x and y positions, simply re-use the existing red ball and change only the extrinsic states. (See Flyweight Saga Part II.)

  • Share/Bookmark

Related posts:

  1. The ActionScript 3.0 Flyweight Saga: Part II Extrinsic States
  2. The Flyweight Design Pattern: Where Shared Objects Solve Storage Problems
  3. The ActionScript 3.0 Flyweight Saga: Part I

18 Responses to “The ActionScript 3.0 Flyweight Saga: Part III Aggregation Aggravation, Stuff on the Stage and the Intrinsic State”


  • As I was going over the code I realized that ‘cir1′ and ‘cir2′ hold references to the exact same object, which is obviously not an accident since that is the whole point of the Flyweight pattern, to reuse objects as much as possible. But then I asked myself how would you modify the extrinsic state of each button without affecting the other. For example, if you set the x and y position of cir2, you are essentially setting the x and y position of cir1 as well since both refer to the same Sprite object. Also, if you remove cir1 from the display, you’ll remove cir2.

    cir1.x = 200; //cir2.x will also increase by 200

    removeChild(cir2) //will also remove cir1’s circle graphic since both
    //cir1’s and cir2’s graphics are located in the same
    //Sprite object. So how do you remove, say cir2,
    //without removing cir1’s graphic?

  • I can’t see the point, too.

  • Hello Thomas and Andres,

    The whole issue of intrinsic and extrinsic states is at the heart of the Flyweight. I’ve re-done everything and put it into a 20pp paper that I’m taking to OOPSLA in Montreal, and I’ll probably put it here once I get their feedback. However, let me see if I can address your queries,

    One of the reasons that the Flyweight is so efficient is that it separates the intrinsic from the extrinsic and further from what you’d call the external. That means that a single object (a graphic in this case) can be re-used (a shared object) as a single instance. The extrinsic states amount to the variation that you allow beyond the intrinsic state. In this case, I used the x and y position along with some parameters for the shape of the object. Once beyound the extrinsic states, some interesting things begin to happen. For example, rotation is what might be called an “external” state. If I rotate any single reference to the object as far as rotation is concerned, the entire block will rotate. The same is true with any other state that was not built in as an extrinsic state. So if rotation is important for individual items (airplanes) I would simply add rotation as an extrinsic state.

    Also, this blog was written more to get developers (like yourself) involved in a discussion of the Flyweight. If you look around at examples, several get it wrong and others really do not use it as it is intended–bacically to take a single intrinsic state and vary it with extrinsic states in side a single instance to save space and increase the execution of a program. The original example in GoF is far better than the one I used because there are so many more references — a word processor re-using the glyph set. The intrinsic value is the character (a,b,c,d, etc.) and the extrinsic is the row and column on the page. In a thousand page book (The Java Bible)the letter “e” may be used 100,000 times. However, with a flyweight, it is rendered once and re-used as a shared object 100,000 times. Multiply that with all of the characters used over 1,000 pages and you can see why the Flyweight is so valuable.

  • Thomas and Andres,

    I believe there are many different interpretations of the Flyweight Pattern. The best solution depends perhaps most on what you are trying to do.

    If you want to be able to move the circles around (etc.) you could choose a structure like the one I described in my comment on Part I. (The example uses soldiers in a game.)

    Basically, here’s what I would do: Each circle is in fact its own instance, but all intrinsic variables and all behavior are put into a static helper class. Because it is static, this code exists in memory only once.

    When a function is called on an instance, the function simply calls its static counterpart. It passes itself as a reference, so that the static function may act on the correct instance. (The ‘with’ keyword comes in handy – saves you from having to rewrite your functions.)

    This keeps all functions very lightweight (flyweight, that is) – they contain only one line of code, namely the call to the static function. It also minimizes the number of variables used by separating the intrinsic ones. The instances you create end up consuming less memory.

    In comparison, Bill’s approach is likely even more efficient, memory wise. By effectively putting multiple graphics in a single instance, we save even more memory. The price is paid in limitations to treating the circles individually, e.g. moving them around, adding event listeners to them, or turning them invisible.

    I’m very curious to hear more opinions on these various approaches!

  • Timo,

    I think your point about memory efficiency vs. flexibility is an important one. In learning algorithms, the importance is placed on memory efficiency, but Timo’s solution is a much better one than mine because it affords more flexibility. I really like the idea of a using a static helper class that can be called to generate instances while not having to pull up more into memory.

    Could you put your Flyweight soldiers together in a working example?

    Thanks,
    Bill

  • William Bill,

    Thanks for your kind words. I’ve just prepared a working example that also shows a difference in memory usage. I’m using 10 soldiers in this example.

    The example is below. Keep in mind that we are still creating instances as normal, which consume their share of memory. The only thing I’m doing differently here is pulling apart all the intrinsics and shoving them into a static helper class, so as to minimize the instances.

    Note from Bill: All of the following block of code goes into the same file. So just make one file with the name “Soldier.as” that will include the Flyweight class. Also, see my comments below.

    ?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
    
    package
    {
    	import flash.display.Sprite;
     
     
     	// Soldier with flyweight
     
    	public class Soldier extends Sprite
    	{
    		public var life:int;
     
     
    		public function Soldier()
    		{
    			life = 10;
     
    			x = Math.random()*200;
    			y = Math.random()*200;
     
    			// draw graphic
    			graphics.beginFill( 0xFFFF00 );
    			graphics.drawCircle( 0, 0, 10 );
    			graphics.endFill();
    		}
     
     
    		public function fireAtYourMaster( master:FlyweightTest )
    		{
    			Flyweight.fireAtYourMaster( this, master );
    		}
     
     
    		public function walk( targetX:Number, targetY:Number )
    		{
    			Flyweight.walk( this, targetX, targetY );
    		}
     
     
    		public function fire( target:Soldier )
    		{
    			Flyweight.fire( this, target );
    		}
    	}
    }
     
     
    class Flyweight
    {
    	private static var damage:int = 4;
     
     
    	public static function fireAtYourMaster( soldier:Soldier, master:FlyweightTest )
    	{
    		with( soldier )
    		{
    			master.reduceHitpoints( damage );
    		}
    	}
     
     
    	public static function walk( soldier:Soldier, targetX:Number, targetY:Number )
    	{
    		with( soldier )
    		{
    			trace( "Walking from (" + x + "," + y + ") to (" + targetX + "," + targetY + ")" );
    			x = targetX;
    			y = targetY;
    		}
    	}
     
     
    	public static function fire( soldier:Soldier, target:Soldier )
    	{
    		with( soldier )
    		{
    			trace( "Firing at: " + target );
    			target.life -= damage;
    		}
    	}
    }
    ?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
    
    package
    {
    	import flash.display.Sprite;
     
     
     	// Normal soldier (similar but non-flyweight)
     
    	public class Soldier2 extends Sprite
    	{
    		private static var damage:int = 4;
     
    		public var life:int;
     
     
    		public function Soldier2()
    		{
    			life = 10;
     
    			x = Math.random()*200;
    			y = Math.random()*200;
     
    			// draw graphic
    			graphics.beginFill( 0xFFFF00 );
    			graphics.drawCircle( 0, 0, 10 );
    			graphics.endFill();
    		}
     
     
    		public function fireAtYourMaster( master:FlyweightTest )
    		{
    			master.reduceHitpoints( damage );
    		}
     
     
    		public function walk( targetX:Number, targetY:Number )
    		{
    			trace( "Walking from (" + x + "," + y + ") to (" + targetX + "," + targetY + ")" );
    			x = targetX;
    			y = targetY;
    		}
     
     
    		public function fire( target:Soldier )
    		{
    			trace( "Firing at: " + target );
    			target.life -= damage;
    		}
    	}
    }
    ?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
    
    package
    {
    	import flash.display.Sprite;
    	import flash.system.System;
     
     
    	// Document Class
     
    	public class FlyweightTest extends Sprite
    	{
    		private var hitpoints:int;
    		private var soldiers:Array;
     
     
    		public function FlyweightTest()
    		{
    			hitpoints = 100;
    			soldiers = new Array();
     
    			trace( "Starting HP: " + hitpoints );
     
    			// create 10 soldiers
    			// have each one fire at us once
    			// outcomment this part to compare soldier memory usage
    			for( var i:int = 0; i < 10; i++ )
    			{
    				soldiers.push( new Soldier() );
    				addChild( soldiers[i] );
    				soldiers[i].fireAtYourMaster( this );
    			}
     
    			trace( "Final HP: " + hitpoints );
     
    			trace( "Memory usage: " + System.totalMemory );
    		}
     
     
    		public function reduceHitpoints( amount:Number )
    		{
    			hitpoints -= amount;
    		}
    	}
    }

    In the document class, you can change 'new Soldier()' to 'new Soldier2()' to create normal soldiers instead of flyweight ones. The memory difference here is 4,096 bytes (4 kB).

    By outcommenting the code that creates the 10 soldiers, we can see that the normal (non-flyweight) soldiers consume 57,344 bytes of memory.

    This means that using flyweights, in this case, saves 4,096 out of 57,344 bytes of memory, which is about 7.1%. Of course, the functions we used are minor. I wouldn't normally use a flyweight in this example. However, I did once extend Sprite (and MovieClip) to incorporate lots of directional functions (bearingTo, lookAt, etc.). That's where it gets interesting. If you have, say, 20 functions of moderate size, try the flyweight pattern and report back here with your own percentage of memory saved!

    It could be like an overclocking contest. William Bill could even throw in a couple o' prizes :P

    There are some final thoughts I'm still pondering on… I'm curious to hear anyone's thoughts.

    - Constants shouldn't need to be put in the flyweight.
    - What about the constructor and destructor (I like destructors)? Logically it would seem effective to put them in the flyweight as well, but I have a bad feeling about it…
    - Why use a helper class? We could use static functions inside the original class, for instance. The effect would be similar. There's no real advantage to either approach above the other. Anyone?

    P.S. William Bill, if I didn't get it done, could you change the code to actual code blocks, please?

  • Hi Timo,

    Interesting example! I ran a test and came up with the following (results from Output window):

    Starting HP: 100 (With Flyweight)
    Final HP: 60
    Memory usage: 23265280

    Starting HP: 100 (Without Flyweight)
    Final HP: 60
    Memory usage: 23281664

    Additional bytes without Flyweight
    16,384

    Unless I missed something, I came up with four times the savings with a flyweight than you did.(16kb vs 4kb) In any event, this is a great example of Flyweight vs. non-Flyweight. I hope some of our other readers will test this and see what they come up with.

    By the way, I put in a dark green background to better show the yellow circles.

    Take care,
    Bill

  • Oh, it’s Bill! I wasn’t paying attention. Sorry ;)

    I had a feeling the memory usage might come out differently. Strange, isn’t it? Interestingly, I’m getting different values today than I was getting yesterday. No changes, I’m telling you. Even crazier, when I run the application now, the memory output is different every time. That didn’t happen yesterday!

    I don’t trust Flash. Honestly.

    If you or anyone here knows how this happens, by all means let me know! I’m a little baffled.

    Take care,
    Timo

    P.S. Some of the actionscript in the last block of code got messed up (some quotes and a ‘less than’ symbol).

  • Hi Timo,

    That is interesting! I’m running the tests on a Mac. Maybe it’s the version of Flash/Flex? However, since you’re running on the same machine with the same software, it should be more consistent. Is it possible that that random distribution may affect the outcome? With the circles grouped it uses less and more scattered uses more? (Wild guess…)

    Cheers,
    Bill

  • Good point. I did consider that the first day I tested, and found no variation. It might have caused the fluctuations the second day, weird as that still may be. I’ll give it a shot without the randomness when I’m at my PC.

    Cheers,
    Timo

  • Hi Bill,

    I have tested with the random outcommented, and then even the graphics outcommented as well. Odly, I would still get fluctuations in the memory usage. Only when I keep lauching the swf in rapid succession does the total memory consumption remain steady.

    I’m still at 4096 kB saved thanks to flyweight.

    Interestingly, I read that C++ keeps only one copy of each function, and sets the ‘this’ pointer when it calls it. That would render this implementation obsolete in C++, and that would make sense. After all, if this solution saves memory at practically no cost, why not let the compiler implement it automatically?

    This leaves me curious as to other languages. AS3 does not use this, C++ does – what would C# do? Objective C? Java?

    I wonder…

    Best regards,
    Timo

  • I did some more research into the flyweight design pattern.

    It turns out that my implementation is, in the traditional sense, ‘wrong’. Either the book I mentioned below Part I of this blog was mistaken, or my interpretation was.

    The flyweight pattern is indeed supposed to be more like you describe it, and is primarily used for saving many glyphs in a text document while needing only one instance for each different formatting style that occurs for that glyph – glyph being an example.

    I believe there is no official design pattern for my approach, but for languages that do not handle this in their compiler, it can be a fine memory savor!

    No wonder C++ is always faster :)

  • Hi Timo,

    Well, if there’s no ‘official design pattern’ why not make one of your own? The Gang of Four certainly wanted to encourage others to develop design patterns that met needs that they did not anticipate in their original catalog.

    Kindest regards,
    Bill

  • That is a great idea.

    Do you know if there is a specific place to publish this kind of thing?

    Cheers!
    Timo

  • Hi Timo,

    The Association for Computing Machinery: Advancing Computing as a Science & Profession has several journals. You can find them here:. The ACM seems to be main organization worldwide for all things computer—the OOPSLA meetings were where the original Design Pattern papers were presented.

    Of course….if you’d like us to publish it on our blog, we’d certainly be interested if ActionScript 3.0 is used!

    Cheers,
    Bill

  • hi guys, i tried Timo’s Soldier example and found out that the Flyweight pattern does not reduce alot of memory consumption.

    here are my results:

    I set the loop to create 10 soldiers:

    [Soldier.as]
    Starting HP: 100
    Final HP: 60
    Memory usage: 2916352

    [Soldier2.as]
    Starting HP: 100
    Final HP: 60
    Memory usage: 2904064

    Now, I set the loop to create 100 soldiers:

    [Soldier1:]
    Starting HP: 100
    Final HP: -300
    Memory usage: 3186688

    [Soldier2:]
    Starting HP: 100
    Final HP: -300
    Memory usage: 3174400

    It seems that the non-flyweight (soldier2.as) use lesser memory than the flyweight (soldier.as)

    Am I missing something?

  • ok i found out whats the problem with the code,

    my first attempt was placing the Flyweight.as as an external class instead of placing within Soldier.as class. As a result, this somehow bloated the memory consumption and makes the non-flyweight candidate a winner.

    My second attempt was copying all the raw code directly and placing into my software, and it produces the same result as Bill (aka William Bill Sanders) which was a 16kb save for creating 10 flyweight soldiers.

    Increasing the amount of soliders to 1000, flyweight soldiers save 28kb.

    [soldier1.as] flyweight
    Starting HP: 100
    Final HP: -3900
    Memory usage: 5697536

    [soldier2.as] non-flyweight
    Starting HP: 100
    Final HP: -3900
    Memory usage: 5726208

    differences: save 28672

  • Good job, Ayu.

    Yeah, I suppose if an extra instance has to be created for every flyweight, that’ll take up a lot of memory of its own.

    Thanks for sharing your results too!
    Timo

Leave a Reply