Sunday, January 21, 2024

Flyweight Design Pattern in C#

The Flyweight design pattern is a structural pattern that focuses on minimizing the memory footprint or computational expenses of an object. It achieves this by sharing as much as possible with related objects, rather than keeping all of the data in each object. This is particularly useful when dealing with a large number of similar objects, as it helps reduce the overall memory consumption and improves performance.

Purpose of Flyweight Pattern:

  • To reduce the number of objects and to conserve memory by sharing objects among multiple contexts.
  • To achieve performance improvement by minimizing the overhead of creating and managing large numbers of similar objects.

The flyweight pattern uses the concepts of intrinsic and extrinsic data.

Intrinsic data is held in the properties of the shared flyweight objects. This information is stateless and generally remains unchanged, if any change occurs it would be reflected among all of the objects that reference the flyweight.

Extrinsic data is computed on the fly means at runtime and it is held outside of a flyweight object. Hence it can be stateful.

Components of the Flyweight Pattern:

  • Flyweight Interface (IFlyweight): Declares the interface for flyweight objects.
  • ConcreteFlyweight (ConcreteFlyweight): Implements the Flyweight interface and represents concrete flyweight objects. It stores intrinsic state, which is the state shared with other flyweights.
  • UnsharedConcreteFlyweight (UnsharedConcreteFlyweight): Represents an unshared flyweight object that cannot be shared. It usually contains extrinsic state that must be unique for each object.
  • FlyweightFactory: Manages flyweight objects and ensures that they are shared properly. It often includes methods to retrieve or create flyweight objects.

Example in C#

Here's an example of how you can implement the Flyweight Design Pattern in C#

Create the Flyweight Interface: Define an interface or an abstract class for the flyweight objects. This interface should declare methods or properties that allow you to access and manipulate the intrinsic state.

namespace FlyweightPattern.FlyweightInterface
{
    /// <summary>
    /// Flyweight interface
    /// </summary>
    public interface IFont
    {
        void SetSize(int size);
        void SetStyle(string style);
        void SetColor(string color);
        void Display(string text);
    }
}

Implement Concrete Flyweights: Create concrete classes that implement the flyweight interface. These classes should store and manage the intrinsic state.

using FlyweightPattern.FlyweightInterface;

namespace FlyweightPattern.ConcreteFlyweight
{
    /// <summary>
    /// Concrete Flyweight
    /// </summary>
    public class ConcreteFont : IFont
    {
        private int size;
        private string style;
        private string color;

        public void SetSize(int size)
        {
            this.size = size;
        }

        public void SetStyle(string style)
        {
            this.style = style;
        }

        public void SetColor(string color)
        {
            this.color = color;
        }

        public void Display(string text)
        {
            Console.WriteLine($"Text: '{text}' | Size: {size} | Style: {style} | Color: {color}");
        }
    }
}

Create a Flyweight Factory: Implement a factory class responsible for managing and sharing flyweight objects. This factory ensures that each unique combination of intrinsic state is represented by a single flyweight instance.

using FlyweightPattern.ConcreteFlyweight;
using FlyweightPattern.FlyweightInterface;

namespace FlyweightPattern.FlyweightFactory
{
    /// <summary>
    /// Flyweight Factory
    /// </summary>
    public class FontFactory
    {
        private Dictionary<string, IFont> fonts = new Dictionary<string, IFont>();
        public IFont GetFont(string key)
        {
            if (!fonts.ContainsKey(key))
            {
                fonts[key] = new ConcreteFont();
            }
            return fonts[key];
        }
    }
}

Client Code: In your client code, use the flyweight factory to create and share flyweight objects. You can then set their intrinsic state as needed and use them in your application.

using FlyweightPattern.FlyweightFactory;
using FlyweightPattern.FlyweightInterface;

FontFactory fontFactory = new FontFactory();

// Create font with different font name
IFont font1 = fontFactory.GetFont("Arial");
IFont font2 = fontFactory.GetFont("Times New Roman");

// Set intrinsic state
font1.SetSize(12);
font1.SetStyle("Regular");
font1.SetColor("Black");

font2.SetSize(14);
font2.SetStyle("Italic");
font2.SetColor("Red");

// Use flyweight objects
font1.Display("Hello, Flyweight Pattern!");
font2.Display("This is a demonstration.");

// Create another font using the same flyweight
IFont font3 = fontFactory.GetFont("Arial");
font3.Display("Same flyweight object");

Console.ReadLine();

Output

Happy coding!! 😊

No comments:

Post a Comment

^ Scroll to Top