Jul 21, 2013

Flyweight Design Pattern

1 comment
The flyweight design pattern allows us to reuse memory spaces in an application when we have lots of objects that are almost identical in nature.

For example, if we are writing a game for a smartphone where the amount of memory is very limited and we need to show many angry birds that are identical in shape. We can have only one place that holds the shape of the angry bird instead of keeping each identical shape in the precious memory.

In flyweight pattern, there is the concept of Intrinsic and Extrinsic state. Intrinsic states are things that are constant and are stored in the memory. Extrinsic states are things that are not constant and needs to be calculated on the fly, and are therefore not stored in the memory.

For example, in the game that we would like to create, the shapes of the Angry Birds are all the same. But their color will change based on how powerful each are. The shapes of the angry birds will be Intrinsic, and the color of the angry bird will be Extrinsic.

UML Class Diagram

  • The FlyweightFactory class is just an indexer that allows us to retrieve the flyweight object when given an index number, since we may have many flyweight objects in application.
  • The IFlyweight interface defines the methods and the properties required for the flyweight objects. The Operation method gets the extrinsic states and the intrinsicState variable holds the intrinsic states.
  • The ConcreteFlyweight class is the actual flyweight object. The intrinsicState variable stores the information that is constant, while the Operation method calculates the extrinsic states on the fly.
When to use Flyweight Pattern
We need to consider following factors when choosing flyweight,
  1. Need to create large number of objects.
  2. Because of the large number when memory cost is a constraint.
  3. When most of the object attributes can be made external and shared.
  4. The application must not mandate unique objects, as after implementation same object will be used repeatedly.
  5. Its better when extrinsic state can be computed rather than stored. 
Flyweight vs Prototype patterns
Both patterns shows some similarities in the UML class diagram, in that both use a manager to store and retrieve the objects in the collection. But there is a clear difference between the two.
The prototype pattern is used to create new objects that are similar in nature (hence it's a creational pattern), while the flyweight pattern is used to allow the application to point to the same instance of the object to save memory (hence it's a structural pattern).

Below are the implementation code and the output of the example using flyweight design pattern. Notice that the intrinsic states are stored in one place only to save memory while the extrinsic states are calculated on the fly.

Implementation
Create Flyweight interface.i.e, IAngryBird
public interface IAngryBird
{
    // intrinsic state
    string Shape { get; }
        
    // extrinsic state
    Color GetColor(int powerLevel);
}

Create Concrete flyweight classes.i.e., SmallAngryBird, LarggeAngryBird
public class SmallAngryBird : IAngryBird
{
    // intrinsic state
    private string _shape = "Circular Shape";
    string IAngryBird.Shape
    {
     get { return _shape; }
    }

    // extrinsic state
    Color IAngryBird.GetColor(int powerLevel)
    {
        if (powerLevel == 0)
            return Color.Red;
        else
            return Color.Yellow;
    }
}
public class LargeAngryBird : IAngryBird
{
    // intrinsic state
    private string _shape = "Rectangular Shape";
    string IAngryBird.Shape
    {
        get { return _shape; }
    }

    // extrinsic state
    Color IAngryBird.GetColor(int powerLevel)
    {
        if (powerLevel == 0)
            return Color.Black;
        else
            return Color.Green;
    }
}

Create Flyweight factory class.i.e,AngryBirdsFactory
public class AngryBirdsFactory
{
    private Dictionary _birds = new Dictionary();

    public void AddAngryBird(int index, IAngryBird bird)
    {
        _birds.Add(index, bird);
    }

    public IAngryBird GetAngryBird(int index)
    {
        return _birds[index];
    }
}

Create a client to use above implemented flyweight pattern,
private void btnFlyweight_Click(object sender, EventArgs e)
{
    // create Angry birds and add to factory
    AngryBirdFactory factory = new AngryBirdFactory();
    factory.AddAngryBird(0, new LargeAngryBird()); 
    factory.AddAngryBird(1, new SmallAngryBird());

    // Access the flyweight objects using index
    IAngryBird a = factory.GetAngryBird(0);
    IAngryBird b = factory.GetAngryBird(1);

    //show intrinsic states, all accessed in memory without calculations
    Console.WriteLine("Intrinsic states...");
    Console.WriteLine("AngryBird of type 0 is " + a.Shape);
    Console.WriteLine("AngryBird of type 1 is " + b.Shape);
    Console.WriteLine();

    // Extrinsic states based on calculations
    Console.WriteLine("Extrinsic states...");
    Console.WriteLine("AngryBird of type 0 is " + a.GetColor(0).ToString());
    Console.WriteLine("AngryBird of type 0 is " + a.GetColor(1).ToString());
    Console.WriteLine("AngryBird of type 1 is " + b.GetColor(0).ToString());
    Console.WriteLine("AngryBird of type 1 is " + b.GetColor(1).ToString());
}

Output
Intrinsic states...
AngryBird of type 0 is Rectangular Shape
AngryBird of type 1 is Circular Shape

Extrinsic states...
AngryBird of type 0 is Color [Black]
AngryBird of type 0 is Color [Green]
AngryBird of type 1 is Color [Red]
AngryBird of type 1 is Color [Yellow]

1 comment :