Flyweight - Design Pattern

Flyweight - Design Pattern

Software Architecture Simplified

ยท

3 min read

Objective ๐ŸŽฏ

Allow to put more objects into the available memory RAM by sharing common parts between multiple objects.

Notes ๐Ÿ“

โ€ข Flyweight object has a single-instance (singleton) and can be reused by other objects.

โ€ข Intrinsic state means that the object can be shared as there is not a โ€œspecificโ€ property in the object that makes it unique. We can consider it also as contextless.

โ€ข Extrinsic state is the opposite of intrinsic, it means that the object has one or more properties that are exclusive of a single instance (context), what prevents the object from being shared.

image.png

โ€ข To use a web browser analogy, a single cached image can be used in different places just varying its size and position, in this scenario the URL never changes (intrinsic property) while the size and position change (extrinsic property).

image.png

Type โœ…

โŒBehavioral: Describes how objects interact/communicate between themselves.

โŒCreational: Describes how to instantiate an object without large and complex.

โœ”๏ธStructural: Describes how objects/classes are composed to form larger structures.

UML ๐Ÿ“

image.png

Participants ๐Ÿ”—

โ€ข Flyweight:

  • Declares an interface to allow flyweights objects to receive extrinsic state (property) and act on it.

โ€ข ConcreteFlyweight:

  • Implements the Flyweight interface
  • Represents a shareable object

โ€ข UnsharedFlyweight:

  • Implements the Flyweight interface
  • Represents a unshareable object

โ€ข FlyweightFactory:

  • Creates and manage flyweight objects
  • Makes sure flyweight objects are created and shared properly

โ€ข Client:

  • Maintains a reference to flyweight(s) object(s)
  • Calls the FlyweightFactory to get shared objects

Sample Code ๐ŸŽฎ

Structural Example ๐Ÿ›๏ธ

image.png

public static class FlyweightStructural
    {
        public static void Execute()
        {
            int lContextVariable = 22;

            FlyweightFactory lFlyweightFactory = new FlyweightFactory();

            Flyweight lFlyweightX = lFlyweightFactory.GetFlyweight("X");
            Flyweight lFlyweightY = lFlyweightFactory.GetFlyweight("Y");
            Flyweight lFlyweightZ = lFlyweightFactory.GetFlyweight("Z");
            Flyweight lFlyweightXAgain = lFlyweightFactory.GetFlyweight("X");

            lFlyweightX.Operation(--lContextVariable);
            lFlyweightY.Operation(--lContextVariable);
            lFlyweightZ.Operation(--lContextVariable);
            lFlyweightZ.Operation(--lContextVariable);

            UnsharedConcreteFlyweight lUnsharedConcreteFlyweight = new UnsharedConcreteFlyweight();
            lUnsharedConcreteFlyweight.Operation(--lContextVariable);
        }
    }

    public class FlyweightFactory
    {
        private Hashtable _Flyweights = new Hashtable();

        public FlyweightFactory()
        {
            _Flyweights.Add("X", new ConcreteFlyweight());
            _Flyweights.Add("Y", new ConcreteFlyweight());
            _Flyweights.Add("Z", new ConcreteFlyweight());
        }

        public Flyweight GetFlyweight(string prKey)
        {
            return ((Flyweight)_Flyweights[prKey]);
        }
    }

    public abstract class Flyweight
    {
        public abstract void Operation(int prUniqueState);
    }

    public class ConcreteFlyweight : Flyweight
    {
        public override void Operation(int prUniqueState)
        {
            Console.WriteLine("ConcreteFlyweight - Context Property: " + prUniqueState);
        }
    }

    public class UnsharedConcreteFlyweight : Flyweight
    {
        public override void Operation(int prUniqueState)
        {
            Console.WriteLine("UnsharedConcreteFlyweight - Context Property: " + prUniqueState);
        }
    }

Output

image.png

Real-world Example ๐Ÿ”ฅ

image.png

public static class FlyweightPractical
    {
        public static void Execute()
        {
            ShapeFactory lShapeFactory = new ShapeFactory();

            Circle lCircle1 = (Circle)lShapeFactory.GetShape("Circle", "Red");
            lCircle1.Draw(40, 65);
            Circle lCircle2 = (Circle)lShapeFactory.GetShape("Circle", "Blue");
            lCircle2.Draw(78,32);
            Circle lCircle3 = (Circle)lShapeFactory.GetShape("Circle", "Blue");
            lCircle3.Draw(15,67);

            Square lSquare1 = (Square)lShapeFactory.GetShape("Square", "Red");
            lSquare1.Draw(99,44);
            Square lSquare2 = (Square)lShapeFactory.GetShape("Square", "Red");
            lSquare2.Draw(88,42);

            Triangle lTriangle1 = (Triangle)lShapeFactory.GetShape("Triangle", "Yellow");
            lTriangle1.Draw(89,34);
            Triangle lTriangle2 = (Triangle)lShapeFactory.GetShape("Triangle", "White");
            lTriangle2.Draw(64,24);
        }
    }

    public class ShapeFactory
    {
        private Hashtable _Shapes = new Hashtable();

        public Shape GetShape(string prShape, string prColor)
        {
            string lUniqueKey = prShape + prColor;
            Shape lResult = ((Shape)_Shapes[lUniqueKey]);

            if (lResult == null)
            {
                switch (prShape)
                {
                    case ("Circle"): _Shapes.Add(lUniqueKey, new Circle()); Console.WriteLine($"Creating Shape \"{prColor} {prShape}\""); break;
                    case ("Square"): _Shapes.Add(lUniqueKey, new Square()); Console.WriteLine($"Creating Shape \"{prColor} {prShape}\""); break;
                    case ("Triangle"): _Shapes.Add(lUniqueKey, new Triangle()); Console.WriteLine($"Creating Shape \"{prColor} {prShape}\""); break;
                    default: break;
                }

                return ((Shape)_Shapes[lUniqueKey]);
            }
            else
            {
                Console.WriteLine($"Shape \"{prColor} {prShape}\" already created, retrieving from cache");
                return lResult;
            }
        }
    }

    public abstract class Shape
    {
        public string _Color { get; set; }
        public abstract void Draw(int prX, int prY);
    }

    public class Circle : Shape
    {
        public override void Draw(int prX, int prY)
        {
            Console.WriteLine($"---Drawing {this._Color} Circle in position: X = {prX}, Y = {prY}");
        }
    }

    public class Square : Shape
    {
        public override void Draw(int prX, int prY)
        {
            Console.WriteLine($"---Drawing {this._Color} Square in position: X = {prX}, Y = {prY}");
        }
    }

    public class Triangle : Shape
    {
        public override void Draw(int prX, int prY)
        {
            Console.WriteLine($"---Drawing {this._Color} Triangle in position: X = {prX}, Y = {prY}");
        }
    }

Output

image.png

Source Code ๐ŸŽฒ

github.com/VictorLins/DesignPatterns

Did you find this article valuable?

Support Victor Lins by becoming a sponsor. Any amount is appreciated!

ย