Extrinsic States
In the first part of the Flyweight Saga, I had the idea that a Flyweight design pattern would be a good idea because it would be useful for cranking out buttons on the stage. However, the comments by the readers have led me to reconsider that idea; so it’s back to the drawing board. This revised Flyweight is going to focus on adding an extrinsic state parameter. Also, I got rid of all but one of the concrete Flyweights and am now down to the FlyButton class only in order to focus on extrinsic states.
Keep in mind that this process is a matter of working out the specific sense of a Flyweight pattern more than it is to show the optimum example. In going over some Flyweight materials from MIT, they suggested having a grasp on other, simpler patterns like the Observer and even MVC before tackling the Flyweight. This was both comforting and worrisome!
Extrinsic State Parameter
To get back on track (somewhat), this new Flyweight includes a parameter for extrinsic states in the Flyweight interface. Because the state is extrinsic, it changes with the Flyweights context. As discussed briefly in Part I of this saga, the extrinsic state changes with the context while the intrinsic state does not. Thus, the extrinsic state is not shareable (a shared object) and the intrinsic is. A concrete class can be sharable or not, but it cannot be if it does not store the intrinsic state. However, both sharable and non-sharable concrete Flyweights can exist. The following summary might be helpful.
Extrinsic state
-
Cannot be shared
Depends on flyweight’s context
Client is responsible for supplying extrinsic state when needed
Intrinsic state
-
Can be shared
Stored (inherent) in the flyweight
Does not depend flyweight’s context
Adding a Numeric State Changer
To get started this first new Flyweight does nothing more than add an extrinsic parameter to the existing Flyweight and adds a few new wrinkles. The Flyweight interface key operation includes a numeric (uint) parameter used as a state change indicator. The intrinsic characteristic of the concrete Flyweight, FlyButton, is nothing more than the part of the trace statement indicating “Fly button #.” The extrinsic value (state) is the extrinsic variable that is incremented with each use.
package { //Interface public interface IFlyweight { function build (extrinsic:uint):void; } } //////// package { //Factory public class Factory { protected var objects:Object = {}; public function Factory () { objects["nav"] = new FlyButton(); objects["send"] = new FlyButton(); objects["about"] = new FlyButton(); } public function Retrieve (key:String, ...rest):IFlyweight { switch (objects[key] != undefined) { case (true) : break; case (false) : objects[key] = rest[0]; break; } return objects[key]; } } } //////// package { //Concrete Flyweight (shared) public class FlyButton implements IFlyweight { public function FlyButton () { } public function build (extrinsic:uint):void { trace ("Fly button #" + extrinsic ); } } } //////// package { import flash.display.Sprite; //Client class public class ButtonMaker extends Sprite { private var extrinsic:uint; public function ButtonMaker() { extrinsic=1; var factory:Factory = new Factory(); var nav:IFlyweight = factory.Retrieve("nav"); //"Nav" created in Factory nav.build(extrinsic++); var launch:IFlyweight = factory.Retrieve("send"); //"Send" created in Factory launch.build(extrinsic++); var about:IFlyweight = factory.Retrieve("about"); //"About " created in Factory about.build(extrinsic++); var playit:IFlyweight = factory.Retrieve ("play", new FlyButton()); playit.build(extrinsic++); } } }
That seems to work fine, and most of the buttons were generated in the Factory, but one is created in the client. Given the nature of the design, that’s fine. You will see the following output:
Fly button #1 Fly button #2 Fly button #3 Fly button #4
The Adding Something a Button Could Use
Keeping in mind that we’re looking for a better way to generate buttons to be placed on the page, we will need to add parameters to the existing interface. The needs are simple and identical for each button: a name, an x position, and a y position. So, all that’s necessary is to add parameters for those values and then add something to the client that generates those values. This next example gets us closer to that goal.
package { //Parameters for button label and x and y values public interface IFlyweight { function build (bname:String,xpos:uint,ypos:uint):void; } } //////// package { //Flyweight Factory public class Factory { protected var objects:Object = {}; public function Factory () { objects["nav"] = new FlyButton(); objects["send"] = new FlyButton(); objects["about"] = new FlyButton(); } public function Retrieve (key:String, ...rest):IFlyweight { switch (objects[key] != undefined) { case (true) : break; case (false) : objects[key] = rest[0]; break; } return objects[key]; } } } //////// package { //Concrete Flyweight public class FlyButton implements IFlyweight { public function FlyButton () { } public function build (bname:String,xpos:uint,ypos:uint):void { trace ("Fly button " + bname+ " is located at " + xpos +","+ypos); } } } //////// package { import flash.display.Sprite; //Client class public class NamePlace extends Sprite { //Client data to provide extrinsic state details private var bnamesA:Array=["Play","About Us","Send","Navigation"]; private var xposA:Array=[20,20,20,20]; private var yposA:Array=[20,40,60,80] public function NamePlace() { var factory:Factory = new Factory(); var nav:IFlyweight = factory.Retrieve("nav"); //"Nav" already exists nav.build(bnamesA.pop(),xposA.pop(),yposA.pop()); var launch:IFlyweight = factory.Retrieve("send"); //"Send" already exists launch.build(bnamesA.pop(),xposA.pop(),yposA.pop()); var about:IFlyweight = factory.Retrieve("about"); //"About " already exists about.build(bnamesA.pop(),xposA.pop(),yposA.pop()); var playit:IFlyweight = factory.Retrieve ("play", new FlyButton()); playit.build(bnamesA.pop(),xposA.pop(),yposA.pop()); } } }
This time the output is going to look a lot more like what we need for the buttons. The name of the button, and it’s x,y location all appear in the output as the following shows:
Fly button Navigation is located at 20,80 Fly button Send is located at 20,60 Fly button About Us is located at 20,40 Fly button Play is located at 20,20
Going back to the comments made on this blog, it’s probably wise to create all of the new buttons in the Factory. Also, we need to take a closer look at what is going on with intrinsic values in the FlyButton class. However, it’s creeping along, and in doing so gets us closer to the goal.

Hi Darren,
I think that this part does a partial clarification on “extrinsic” states, but I still feel, I’ve got a ways to go. In looking at the GoF example it seems that all of the extrinsic states are generated by the other concrete classes. My big problem is that I can only do this in between other projects that pay the bills! If I were asked what my hobbies are, “Design Patterns” would be my reply.(That might generate a “get a life…” reply, but that’s what it is right now!)
I was invited to present again at OOPSLA in Montreal, and I’m going to use the Flyweight saga as a way to navigate through understanding this thing better. OOPSLA is where DPs originated, and this time I’m going to do my best to meet the GoF (minus 1 who died). It’s sort of like planting the ActionScript flag on the moon — all of these people are Java, C and increasingly C# folks. Last year in the session, they fried the Singleton and presented the the Symetric Proxy DP (that’s in the book) and so this year I’m going to see who else may possibly attend because it’s in such a cool place–Montreal.
Bill
@Bill,
If you think flying the AS flag is strange, I’ll be flying the ColdFusion flag :-> I’m doing a practitioners report on a high volume software product line I developed in CF and will be presenting at the co-located Domain Specific Modeling forum on automating transformations of statements in DSLs based upon a catalog of types of grammatical transforms to the underlying DSLs.
Please feel free to drop me a line if you’re attending - I’ve never been before, so it would be great to know someone - if only in passing!
Hi Peter,
I’ll be presenting in the Killer Example Workship. This group is focused on coming up with killer examples and processes for teaching university students design patterns. We’re scheduled for October 21 at 12:30 in Montreal. Also, I’ll be going to the educational symposium on OOP in the classroom.
My favorite quote came from someone on my panel last year who was presenting a new DP. I asked him if I could use Flash Media Server as a remote proxy in his model, and he said I could use smoke signals if I wanted—the point being that the structure of the design and not the tools (language) used to achieve the structure is the focal point. So like FMS, I’m certain that CF will be welcomed as well to OOPSLA. The people there are so freakin’ bright you’ll be amazed!
Anyway, I’m planning on using the Flyweight Saga (which better be a completed story by then!) to walk students through a flawed idea to a deeper understanding of what’s going on in the structure of the design pattern. What little I’ve done so far with DPs in the classroom ends up with students copying and pasting or just making minor changes to existing code. I’m putting this up as a way to trip over a few mis-assumptions and lead to a deeper and clearer understanding. (I’m always going through that process myself!).
Hope to see everyone in Montreal,
Bill