9

In my understanding the purpose of the flyweight pattern is to decrease memory footprint and increase performance by sharing common, extrinsic state. Why would anyone prefer to implement the pattern over storing the shared state in static fields?

Consider the following example: http://www.oodesign.com/flyweight-pattern-wargame-example-java-sourcecode.html

enter image description here

If I am right then the point in this example is to share the common state (soldierGraphicalRepresentation object) between all instances of the SoldierClient class by holding a reference to a single SoldierImp object.

Why would I hassle with implementing this design? I would be tempted to declare the SoldierClient class as follows:

public class SoldierClient implements Soldier 
{
    protected static Object soldierGraphicalRepresentation;
    private int currentLocationX;
    private int currentLocationY;

    static SoldierImp()
    {
        soldierGraphicalRepresentation = LoadGraphicalRepresentation();
    }

    public void moveSoldier(int previousLocationX, int previousLocationY, int newLocationX, int newLocationY) {
        // do stuff with the graphical representation

    }
}

This way all instances of the SoilderClient share a reference to the same soldierGraphicalRepresentation object and the same goal is achieved. Am I wrong?

Philip Allgaier
  • 3,505
  • 2
  • 26
  • 53
Tamas Pataky
  • 353
  • 4
  • 16
  • 1
    Because you have several shared states? I'm not sure I understand the question. You might want to provide example code for what you mean. – JB Nizet Feb 23 '13 at 13:57

2 Answers2

12

The point of the pattern is that you can have 200 "big red" soldiers sharing the same "big red" graphical representation, 300 "small blue" soldiers sharing the same "small blue" graphical representation, etc. If you make the graphical representation static, all the soldiers will be identical.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • in other words, a flyweight acts as a "prototype" referenced from many objects to save memory – mantrid Feb 23 '13 at 14:51
  • What if you have a static collection of different graphical representations? This patterns seems to be very convoluted to me and it is more like an antipattern – Tamas Pataky Feb 23 '13 at 14:52
  • 3
    Then every soldier will have a reference to one of the graphical representations of this static collection. Assuming the list is of size 5, and the number of soldiers is 1,000,000, you'll have 5 instances of graphical representation, instead of 1,000,000. That's the point of the pattern. – JB Nizet Feb 23 '13 at 14:54
  • Static variables are shared between all class instances so you would still only have 5 instances of graphical representations and 1,000,000 references to them. The pattern wouldn't save any memory. – Tamas Pataky Feb 23 '13 at 15:09
  • Of course it would save memory. Let's say a soldier is represented by an image of 10 * 100 pixels, 4 bytes per pixels. That makes 4,000 bytes per graphical representation. With 5 instances, you need 20,000 bytes (20 KB). With 1,000,000 graphical representations, you need 4,000,000,000 bytes (4 GB). What costs is not the *reference* to the graphical representation (which just needs a 4-byte pointer), but the graphical representation itself. – JB Nizet Feb 23 '13 at 15:16
  • No, you have a static collection of graphicalRepresentation objects, which is shared. This collection is associated with the type SoilderClient. So you could just say: SolderClient.GraphicalRepresentationCollection["bigBlue"] and that would return one of the 5 objects without having ANY instances of type SoilderClient. The number of SoilderClient objects does not affect the number of graphicalRepresentations. You would only ever have 5 of them. Those 5 objects are constructed when the type SoldierClient is loaded and they exist until the execution of your program finishes. Right? – Tamas Pataky Feb 23 '13 at 15:24
  • How would a soldier know that it must use SolderClient.GraphicalRepresentationCollection["bigBlue"] and not SolderClient.GraphicalRepresentationCollection["smallRed"] or SolderClient.GraphicalRepresentationCollection["mediumGreen"]? Answer: by storing a reference to one of the static graphical representations (passed at creation time). So that's the flyweight pattern: a single heavyweight object is shared between dozens of objects sharing common state. – JB Nizet Feb 23 '13 at 15:28
  • 1
    How about SoilderClient mySoldier = new SoilderClient(SolderClient.GraphicalRepresentationCollection["smallRed"])? at construction time or mySolder.SetGraphicalRepresentation(SolderClient.GraphicalRepresentationCollection["smallRed"]) at any later stage? – Tamas Pataky Feb 23 '13 at 15:30
  • 1
    Yes, that's it. You just used the flyweight pattern. Not using it would be `SoldierClient mySoldier = new SoldierClient(new SmallRedGraphicalRepresentation());` – JB Nizet Feb 23 '13 at 15:30
3

Static fields work, no matter how many red/green/blue graphical representations you may have. The only problem with static fields is that they break Single Responsibility Principle. As you see, your SoldierClient class has two jobs:

  1. managing a pool of graphical representations
  2. the job of a typical SoldierClient

With this design, it's very difficult to reuse one of these two jobs in another context. For example, the pool cannot be reuse for Monster objects which also need to share graphical representations; the typical SoldierClient cannot be used in another context which has nothing to do with a pool.

Nghia Bui
  • 3,694
  • 14
  • 21