C# Flyweight Design Pattern

Summary: in this tutorial, you will learn how to use the C# flyweight pattern to reduce memory usage by sharing data across similar objects.

Introduction to the C# Flyweight pattern

The Flyweight pattern is a structural design pattern that aims to reduce memory usage by sharing data across similar objects.

In this pattern, you create a set of lightweight objects to represent common data shared across multiple objects. These lightweight objects are also called flyweights, which contain only the data that is unique to each object.

In practice, you use the Flyweight pattern when you have to create a large number of objects, but each object has only a small amount of unique data. By using the Flyweight pattern, you can reduce the memory usage of the application significantly.

One practical example of using the Flyweight pattern is in a rich text editor application where you need to manage a large number of character objects that represent the text. In this application, each character object has font, size, and color, which are the same for all characters of the same style.

To manage flyweights, you can create a pool of flyweights to represent the common data (font, size, and color) shared among many characters. Each character object then contains a reference to the corresponding flyweight object, rather than duplicating the same data.

For example, imagine that you want to create a document that contains a lot of text with different font styles, sizes, and colors. Instead of creating a new object for each character, you can create a flyweight object for each style and size combination, and then assign a reference to that flyweight object to each character object that shares that style and size combination.

By doing this, you can reduce the memory usage of the rich text application significantly. Because the application doesn’t create many duplicate objects for the same style and size combinations.

On top of that, the flyweight pattern can improve the performance of the application because it may reduce the time for creating and initializing many objects.

This UML diagram illustrates how the flyweight pattern:

c # Flyweight pattern

C# Flyweight pattern example

The following program demonstrates how to implement the Flyweight design pattern in C#:

namespace FlyweightPattern;

// Flyweight interface
public interface ICharacter
{
    void Display();
}

// Concrete flyweight class
public class Character : ICharacter
{
    private readonly char _symbol;
    private readonly int _size;
    private readonly string _font;

    public Character(char symbol, int size, string font)
    {
        _symbol = symbol;
        _size = size;
        _font = font;
    }

    public void Display()
    {
        Console.WriteLine($"Symbol: {_symbol}, Size: {_size}, Font: {_font}");
    }
}

// Flyweight factory class
public class CharacterFactory
{
    private readonly Dictionary<string, ICharacter> _characters = new();

    public ICharacter GetCharacter(char symbol, int size, string font)
    {
        var key = symbol.ToString() + size.ToString() + font;

        if (!_characters.ContainsKey(key))
        {
            _characters.Add(key, new Character(symbol, size, font));
        }

        return _characters[key];
    }
}

// Client code
public class Client
{
    static void Main(string[] args)
    {
        var factory = new CharacterFactory();

        var char1 = factory.GetCharacter('A', 12, "Arial");
        char1.Display();

        var char2 = factory.GetCharacter('B', 14, "Times New Roman");
        char2.Display();

        var char3 = factory.GetCharacter('A', 12, "Arial");
        char3.Display();

    }
}Code language: C# (cs)

How it works.

First, define the ICharacter interface that has a method Display() that shows a character to the console:

public interface ICharacter
{
    void Display();
}Code language: C# (cs)

Second, define the Character class that implements the ICharacter interface:

public class Character : ICharacter
{
    private readonly char _symbol;
    private readonly int _size;
    private readonly string _font;

    public Character(char symbol, int size, string font)
    {
        _symbol = symbol;
        _size = size;
        _font = font;
    }

    public void Display()
    {
        Console.WriteLine($"Symbol: {_symbol}, Size: {_size}, Font: {_font}");
    }
}Code language: C# (cs)

The Character class has three properties symbol, size, and font. It also implements the Display() method that shows these properties to the console.

Third, define the CharacterFactory class that is responsible for managing the creation and sharing of flyweight objects:

public class CharacterFactory
{
    private readonly Dictionary<string, ICharacter> _characters = new();

    public ICharacter GetCharacter(char symbol, int size, string font)
    {
        var key = symbol.ToString() + size.ToString() + font;

        if (!_characters.ContainsKey(key))
        {
            _characters.Add(key, new Character(symbol, size, font));
        }

        return _characters[key];
    }
}Code language: C# (cs)

Finally, define the Client class that uses the CharacterFactory to obtain flyweight objects for different characters with different sizes and fonts:

public class Client
{
    static void Main(string[] args)
    {
        var factory = new CharacterFactory();

        var char1 = factory.GetCharacter('A', 12, "Arial");
        char1.Display();

        var char2 = factory.GetCharacter('B', 14, "Times New Roman");
        char2.Display();

        // use the flyweight instead of creating new object
        var char3 = factory.GetCharacter('A', 12, "Arial"); 
        char3.Display();

    }
}
Code language: JavaScript (javascript)

Notice that when you request a flyweight object, the CharacterFactory first checks if an object with the same key (symbol, size, and font) already exists in its internal dictionary.

If the object does not exist, the CharacterFactory creates a new Character object and adds it to the dictionary. Otherwise, CharacterFactory returns the existing object.

When you run the program, you should see the output displaying the symbol, size, and font of each character object.

Because the third character object is a duplicate of the first one, the CharacterFactory returns the existing object instead of creating a new one.

Summary

  • Use the C# flyweight pattern to reduce memory usage by sharing data across similar objects.
Was this tutorial helpful ?