Flyweight Design pattern falls under Structural Pattern of Gang of Four (GOF) Design Patterns in .Net. Flyweight pattern tries to reuse already existing similar kind objects by storing them and creates a new object when no matching object is found. In this article, I would like to share what is flyweight pattern and how is it work?
Flyweight pattern is used to reduce the number of objects created, to decrease memory and resource usage. As a result, it increases performance.
Flyweight pattern tries to reuse already existing similar kind objects by storing them and creates a new object when no matching object is found.
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.
The UML class diagram for the implementation of the flyweight design pattern is given below:
The classes, interfaces, and objects in the above UML class diagram are as follows:
This is an interface which defines the members of the flyweight objects.
This is a class which Inherits from the Flyweight class.
This is a class which Inherits from the Flyweight class and enables sharing of information, it is possible to create instances of concrete flyweight classes that are not shared.
This is a class which holds the references of already created flyweight objects. When the GetFlyweight method is called from client code, these references are checked to determine if an appropriate flyweight object is already present or not. If present, it is returned. Otherwise, a new object is generated, added to the collection and returned.
public class FlyweightFactory { private Hashtable _flyweights = new Hashtable(); public Flyweight GetFlyweight(string key) { if (_flyweights.Contains(key)) { return _flyweights[key] as Flyweight; } else { ConcreteFlyweight newFlyweight = new ConcreteFlyweight(); // Set properties of new flyweight here. _flyweights.Add(key, newFlyweight); return newFlyweight; } } } public interface Flyweight { void StatefulOperation(object o); } public class ConcreteFlyweight : Flyweight { public void StatefulOperation(object o) { Console.WriteLine(o); } } public class UnsharedFlyweight : Flyweight { private object _state; public void StatefulOperation(object o) { _state = o; Console.WriteLine(o); } }
The classes, interfaces, and objects in the above class diagram can be identified as follows:
ShapeObjectFactory- FlyweightFactory class.
IShape - Flyweight interface.
Circle & Rectabgle - ConcreteFlyweight class.
/// <summary> /// The 'Flyweight' interface /// </summary> interface IShape { void Print(); } /// <summary> /// A 'ConcreteFlyweight' class /// </summary> class Rectangle : IShape { public void Print() { Console.WriteLine("Printing Rectangle"); } } /// <summary> /// A 'ConcreteFlyweight' class /// </summary> class Circle : IShape { public void Print() { Console.WriteLine("Printing Circle"); } } /// <summary> /// The 'FlyweightFactory' class /// </summary> class ShapeObjectFactory { Dictionary<string, IShape> shapes = new Dictionary<string, IShape>(); public int TotalObjectsCreated { get { return shapes.Count; } } public IShape GetShape(string ShapeName) { IShape shape = null; if (shapes.ContainsKey(ShapeName)) { shape = shapes[ShapeName]; } else { switch (ShapeName) { case "Rectangle": shape = new Rectangle(); shapes.Add("Rectangle", shape); break; case "Circle": shape = new Circle(); shapes.Add("Circle", shape); break; default: throw new Exception("Factory cannot create the object specified"); } } return shape; } } class Program { static void Main(string[] args) { ShapeObjectFactory sof = new ShapeObjectFactory(); IShape shape = sof.GetShape("Rectangle"); shape.Print(); shape = sof.GetShape("Rectangle"); shape.Print(); shape = sof.GetShape("Rectangle"); shape.Print(); shape = sof.GetShape("Circle"); shape.Print(); shape = sof.GetShape("Circle"); shape.Print(); shape = sof.GetShape("Circle"); shape.Print(); int NumObjs = sof.TotalObjectsCreated; Console.WriteLine("\nTotal No of Objects created = {0}", NumObjs); Console.ReadKey(); } }
Flyweight is used when there is a need to create a large number of objects of almost similar nature and storage cost is high.
A few shared objects can replace many unshared ones.
Most of the state can be kept on disk or calculated at runtime.