Flyweight Design Pattern in C#

Flyweight Design Pattern in C# with Examples

In this article, I will discuss the Flyweight Design Pattern in C# with Examples. Please read our previous article discussing the Composite Design Pattern in C# with Examples. The Flyweight Design Pattern falls under the category of Structural Design Pattern. As part of this article, we will discuss the following pointers.

  1. What is the Flyweight Design Pattern?
  2. Understanding the Flyweight Design Pattern with One Real-Time Application.
  3. Understanding the Different States in the Flyweight Design Pattern.
  4. Understanding the Flyweight Design Pattern Class or UML Diagram.
  5. Flyweight Design Pattern Implementation in C#.
  6. When to use the Flyweight Design Pattern in Real-Time application?
What is the Flyweight Design Pattern?

The Flyweight Design Pattern reduces the number of objects created, decreases memory footprint, and increases performance. It’s especially useful when many objects share some common properties.

That means the Flyweight Design Pattern is used when there is a need to create many objects of almost similar nature. A large number of objects means it consumes a large amount of memory, and the Flyweight Design Pattern provides a solution for reducing the load on memory by sharing objects.

For example, you have one image, and you want thousands of copies of that image. There are two ways to achieve that. In the first approach, we can get the printouts 1000 times that image. In the second approach, we can get a printout of that image, then we can use that printout, and then we can take 999 xeroxes of that image. Suppose the printout for one image is 2 USD. Then the total amount required is 1000*2=2000USD. If the Xerox price is 1 USD, then the total amount required is 999*1=999 USD, and one printout is 2 USD, so a total of 1001 USD. So, we can save much amount if we follow the second approach. This is also the same in programming. We can achieve this by using the Flyweight Design Pattern in C#.

Example to Understand Flyweight Design Pattern in C#:

Please look at the following image to better understand the Flyweight Design Pattern. As you can see in the following image, we created and stored one circle object in the Cache. Here, the circle object we stored in the cache has no color. Suppose, let’s say, we have to create 90000 circle objects in green and 90000 circle objects in blue. Again, we must create 80000 circle objects, which are orange, and 70000 circle objects in black. If you notice, all the circle object shapes are the same, only the color changes.

Flyweight Design Pattern in C# with Examples

As per the Flyweight Design Pattern, we can improve the performance by creating the circle object only once time and reusing that circle object many times to create different types of colors. Suppose you want to create 90000 circle objects with green color, then what you can do is. Instead of creating new circle objects every time and filling them with green color, you can get the circle object from the Cache and fill it with green color. In the same way, you can create 90000 circle objects with green color. So, in this way, we can improve the application’s performance using the Flyweight Design Pattern in C#.

Different States in Flyweight Design Pattern in C#:

In Flyweight Design Pattern, there are two states, i.e., Intrinsic and Extrinsic.

Intrinsic states are things that are Constants and Stored in Memory. On the other hand, Extrinsic states are things that are not constant and need to be calculated on the Fly; hence, they can not be stored in memory.

In our example, the Circle Shape is constant (not changed). That means whether it is a green or black color circle object, the shape of the circle object will be the same. So, we need to store this circle object in the memory, i.e., in the cache. And as it is stored in the memory and as it is constant, it belongs to the Intrinsic State.

The Extrinsic state is the color of the circle object, i.e., for one circle object, the color is black, and for other circle objects, the color is green. The color is not constant, and it is calculated on the fly. Therefore, the color is not stored in the memory. As a result, the color belongs to the Extrinsic state. Now, if you read the definition, you will understand the flyweight design pattern very clearly.

Real-Time Example of Flyweight Design Pattern in C#:

Let us understand the Flyweight Design Pattern in C# with one Real-Time Example. Please have a look at the following image. Most of us know the Angry Bird’s video game. Suppose, in the Angry Birds video game, we want to create 50,000 angry birds with red color. And, if we create new 50,000 angry birds and fill them with red color, then it will occupy more memory and create memory issues. So, to avoid this memory issue problem, what we can do here is we can create only one angry bird without any color and put it in the Cache. Then, whenever we need any new angry bird object, we need to get the angry bird object from the cache and fill it with red color. So, in this way, we will not create 50,000 angry bird objects.

Real-Time Example of Flyweight Design Pattern in C#

In this example, the shape of the angry bird is constant and stored in the memory, so the shape of the angry bird is in an Intrinsic state. The color of Angry Bird is an extrinsic state because it is not constant. One time, the color is red; another time, the color may be black. That means the color varies on the fly.

Flyweight Design Pattern Class or UML Diagram:

Let us understand the Class Diagram or UML Diagram and understand the different components involved in the Flyweight Design Pattern in C#. For a better understanding, please have a look at the following diagram.

Flyweight Design Pattern Class or UML Diagram

The following are the three components involved in the Flyweight Design Pattern.

  1. Flyweight: The Flyweight interface enables sharing but does not enforce it. The concrete objects that implement this interface can either be shared or unshared. This will be an interface that defines the members of the flyweight objects.
  2. ConcreteFlyweight: The ConcreteFlyweight class implements the Flyweight interface and adds storage for the intrinsic state. It must be shareable; any state we store in this object should be intrinsic.
  3. FlyweightFacory: The FlyweightFacory has the GetFlyweight method, and you must pass the key to this method. Based on the key, it will check whether the flyweight object is in the cache. If it is there, then it will return that existing flyweight object. If it is not there, then it will create a new flyweight object, add that object to the cache, and return that flyweight object.
Implementing Flyweight Design Pattern in C#:

Suppose in your application you want to create 240000 circle objects with different colors, as shown in the below image.

Implementing Flyweight Design Pattern in C#

Let us implement the above example using the Flyweight Design Pattern using C# step by step to improve the application’s overall performance.

Step 1: Creating Flyweight Interface

Create an interface named IShape.cs and copy and paste the following code. This interface declares one abstract method, i.e., Draw(). This method needs to be implemented by the concrete classes.

namespace FlyweightDesignPattern
{
    // Flyweight Interface
    // This is an interface that defines the members of the flyweight objects.
    public interface IShape
    {
        void Draw();
    }
}
Step 2: Creating ConcreteFlyweight

Create a class file named Circle.cs, then copy and paste the following code. As you can see, this class implements the IShape interface and provides the implementation for the Draw() method. Basically, the Draw method will draw a circle. The circle has four attributes, i.e., Color, X Coordinate, Y Coordinate, and Radius. Further, if you notice, the X Coordinate, Y Coordinate, and Radius are fixed, i.e., the shape of the circle is fixed. The color will vary on the fly, i.e., change at run time. So, we created one method, i.e., SetColor, to set the color of a circle object at runtime.

using System;
namespace FlyweightDesignPattern
{
    // ConcreteFlyweight
    // This is a class which is Inherits from the Flyweight Interface.
    public class Circle : IShape
    {
        public string Color { get; set; }

        //The following Properties Values are going to be the same for all Circle Shape Object
        private readonly int XCor = 10;
        private readonly int YCor = 20;
        private readonly int Radius = 30;

        //For Each Circle Object, we need to call the Following Method to set the Color
        public void SetColor(string Color)
        {
            this.Color = Color;
        }

        public void Draw()
        {
            Console.WriteLine(" Circle: Draw() [Color : " + Color + ", X Cor : " + XCor + ", YCor :" + YCor + ", Radius :" + Radius);
        }
    }
}
Step 3: Creating FlyweightFactory

Create a class file named ShapeFactory.cs and copy and paste the following code. Here, we created one dictionary collection object that will act as a Cache for our application. The dictionary object takes two parameters, i.e., the first one is the key, which is a string type, and the second parameter is its value, i.e., the shape object. It has the GetShape method, which will take ShapeType as a parameter (in our example, it is a circle). Then, it will check whether that key is present in the dictionary. If the key is present in the dictionary, then it simply returns the shape object, i.e., stored against that key in the dictionary. If the key is not present in the dictionary, it will create a brand new shape object, add that object to the dictionary, and finally return that object to the caller.

using System;
using System.Collections.Generic;
namespace FlyweightDesignPattern
{
    // FlyweightFacory
    // This is a factory class used to create concrete objects of the ConcreteFlyweight type
    public class ShapeFactory
    {
        //The Following Dictionary is going to act as our Cache Memory
        private static Dictionary<string, IShape> shapeMap = new Dictionary<string, IShape>();

        //The following Method is going to return the Shape Object
        public static IShape GetShape(string shapeType)
        {
            IShape shape = null;
            if (shapeType.Equals("circle", StringComparison.InvariantCultureIgnoreCase))
            {
                //If the key shapeType i.e. circle is stored in the Cache, then return the value of the key
                //else create circle object, store it in the Cache, and return the object
                if (shapeMap.TryGetValue("circle", out shape))
                {
                }
                else
                {
                    shape = new Circle();
                    shapeMap.Add("circle", shape);
                    Console.WriteLine(" Creating circle object with out any color in shapefactory \n");
                }
            }
            return shape;
        }
    }
}
Step4: Client

The Main method of the Program class is going to be the Client. So, please modify the Main method of the Program class as shown below. This client class is used to explain the Flyweight Design Pattern. The following code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace FlyweightDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            //Creating Circle Objects with Red Color
            Console.WriteLine("\n Red color Circles ");
            for (int i = 0; i < 3; i++)
            {
                Circle circle = (Circle)ShapeFactory.GetShape("circle");
                circle.SetColor("Red");
                circle.Draw();
            }

            //Creating Circle Objects with Green Color
            Console.WriteLine("\n Green color Circles ");
            for (int i = 0; i < 3; i++)
            {
                Circle circle = (Circle)ShapeFactory.GetShape("circle");
                circle.SetColor("Green");
                circle.Draw();
            }

            //Creating Circle Objects with Blue Color
            Console.WriteLine("\n Blue color Circles");
            for (int i = 0; i < 3; ++i)
            {
                Circle circle = (Circle)ShapeFactory.GetShape("circle");
                circle.SetColor("Green");
                circle.Draw();
            }

            //Creating Circle Objects with Orange Color
            Console.WriteLine("\n Orange color Circles");
            for (int i = 0; i < 3; ++i)
            {
                Circle circle = (Circle)ShapeFactory.GetShape("circle");
                circle.SetColor("Orange");
                circle.Draw();
            }

            //Creating Circle Objects with Black Color
            Console.WriteLine("\n Black color Circles");
            for (int i = 0; i < 3; ++i)
            {
                Circle circle = (Circle)ShapeFactory.GetShape("circle");
                circle.SetColor("Black");
                circle.Draw();
            }

            Console.ReadKey();
        }
    }
}
Output:

When to use the Flyweight Design Pattern in Real-Time application?

Advantages of Flyweight Design Pattern:
  • Reduced Memory Footprint: Significantly reduces memory usage when dealing with large numbers of similar objects.
  • Improved Performance: This can improve performance in systems where object instantiation and garbage collection are bottlenecks.
When to use the Flyweight Design Pattern in Real-Time application?

The Flyweight Design Pattern in C# is particularly useful in scenarios where:

  • Efficient Resource Management: When your application needs to manage a large number of similar objects, keeping an instance of each object is resource-intensive. The Flyweight pattern helps in sharing objects to reduce the memory footprint.
  • Shared State Objects: In situations where objects can have shared states (intrinsic state) that can be factored out and shared among multiple objects. Flyweight allows for sharing common parts to reduce the system’s memory usage.
  • High Memory Usage Due to Object Quantity: If your application risks using a large amount of memory due to the sheer volume of objects, the Flyweight pattern can reduce memory consumption by sharing objects instead of creating new ones.
  • Performance-Critical Applications: In performance-critical applications, the overhead of object creation and garbage collection needs to be minimized, especially in constrained environments such as games or mobile applications.
  • Immutable Object Requirements: When dealing with immutable objects, their state cannot change after they are constructed. Flyweight makes it easier to manage and share these immutable objects.
  • Graphical Applications: Commonly used in graphical applications, like graphic editors or games, where many objects (like trees, bullets, or characters) look similar but might differ in some attributes (like position or size).
  • Text Processing: In text processing applications where you need to represent each character in a document, using a flyweight can significantly reduce memory usage, as each character type can be represented as a single object.
  • UI Controls: When dealing with user interface elements, similar objects (like buttons, icons, or menu items) are used repeatedly across the application.

In the next article, I will discuss Multiple Real-Time Examples of the Flyweight Design Pattern in C#. In this article, I explain the Flyweight Design Pattern in C# with Examples. I hope you enjoy this Flyweight Design Pattern in C# with Examples article.

4 thoughts on “Flyweight Design Pattern in C#”

  1. In the factory, you should try to get the value from the map first.

    Because if you have several shape (circle, rectangle, square, etc), you don’t want to repeat the mapShape.TryGetValue

    Something like
    GetShape(string shapeType) {
    if (!mapShape.TryGetValue(shapeType, out Shape shape)
    {
    if (shape.Equals(“circle”))
    else …
    }
    return shape;
    }

  2. The purpose of the function Factory is to create an object of a custom type, why check for Type? This is actually a cache, as I think it is enough to try to get the value by the key, because the key is the Type of the object.

Leave a Reply

Your email address will not be published. Required fields are marked *