Flyweight Design Pattern in C# with Example

1. Definition

The Flyweight Design Pattern aims to reuse already existing similar kind objects by storing them and creating a new object only when no matching object is found. It’s a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory.

2. Problem Statement

Let's consider a scenario where an application needs to represent a large number of objects, but many of them might have overlapping state. Instantiating individual objects for each of them could consume a lot of memory and resources.

3. Solution

The Flyweight pattern tackles this problem by separating the intrinsic state (shared) from the extrinsic state (external). Objects share their intrinsic state, stored in the flyweight, and pass around the extrinsic state in method calls.

4. Real-World Use Cases

1. Representing characters in a word processor where each character's glyph representation can be reused.

2. Rendering forests in games where many trees might share the same mesh but differ in position, scale, and orientation.

5. Implementation Steps

1. Split object properties into intrinsic (shared) and extrinsic (unique).

2. Create a factory to manage flyweight objects and ensure sharing.

3. Ensure that the client code uses the flyweight factory instead of the new keyword for creating objects.

6. Implementation in C#

// Flyweight class
public class TreeType
{
    public string Name { get; private set; }
    public string Color { get; private set; }

    public TreeType(string name, string color)
    {
        Name = name;
        Color = color;
    }

    public void Display(int x, int y)
    {
        Console.WriteLine($"Tree of type {Name} with color {Color} displayed at ({x}, {y})");
    }
}

// Factory class
public class TreeTypeFactory
{
    private Dictionary<string, TreeType> _treeTypes = new Dictionary<string, TreeType>();

    public TreeType GetTreeType(string name, string color)
    {
        string key = $"{name}-{color}";
        if (!_treeTypes.ContainsKey(key))
        {
            _treeTypes[key] = new TreeType(name, color);
        }
        return _treeTypes[key];
    }
}

public class Forest
{
    private List<Tree> _trees = new List<Tree>();

    public void PlantTree(int x, int y, string name, string color, TreeTypeFactory factory)
    {
        TreeType type = factory.GetTreeType(name, color);
        Tree tree = new Tree(x, y, type);
        _trees.Add(tree);
    }

    public void DisplayForest()
    {
        foreach (var tree in _trees)
        {
            tree.Display();
        }
    }
}

public class Tree
{
    private int _x;
    private int _y;
    private TreeType _type;

    public Tree(int x, int y, TreeType type)
    {
        _x = x;
        _y = y;
        _type = type;
    }

    public void Display()
    {
        _type.Display(_x, _y);
    }
}

public class Program
{
    public static void Main()
    {
        TreeTypeFactory treeFactory = new TreeTypeFactory();
        Forest forest = new Forest();

        forest.PlantTree(1, 2, "Oak", "Green", treeFactory);
        forest.PlantTree(5, 7, "Pine", "DarkGreen", treeFactory);
        forest.PlantTree(3, 6, "Oak", "Green", treeFactory);

        forest.DisplayForest();
    }
}

Output:

Tree of type Oak with color Green displayed at (1, 2)
Tree of type Pine with color DarkGreen displayed at (5, 7)
Tree of type Oak with color Green displayed at (3, 6)

Explanation:

In the provided example, instead of creating individual tree objects for each tree in our forest, we use a TreeType flyweight that contains shared data (like tree name and color). The TreeTypeFactory ensures that we reuse existing TreeType objects and only create new ones when necessary. The Forest and Tree classes deal with the unique properties of each tree, like their positions.

7. When to use?

1. Use the Flyweight Pattern when you have a large number of similar objects and you want to reduce memory usage.

2. When the object's intrinsic state can be shared and the extrinsic state can be passed in from the outside.


Comments