13
SepFlyweight Design Pattern
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?
What is Flyweight Pattern
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.
Flyweight Pattern - UML Diagram & Implementation
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:
Flyweight
This is an interface which defines the members of the flyweight objects.
ConcreteFlyweight
This is a class which Inherits from the Flyweight class.
UnsharedFlyweight
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.
FlyweightFactory
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.
C# - Implementation Code
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); } }
Flyweight Pattern - Example
Who is what?
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.
C# - Sample Code
/// <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 Pattern Demo - Output
When to use it?
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.
What do you think?
I hope you will enjoy the Flyweight Pattern while designing your software. I would like to have feedback from my blog readers. Your valuable feedback, question, or comments about this article are always welcome.
FAQs
Q1. How does Flyweight reduce memory consumption?
Q2. What types of systems benefit most from the Flyweight Pattern?
- Graphics rendering: Games or graphical user interfaces.
- Text processing: Text editors or document formatting systems.
- Geospatial mapping: Applications that render large maps with repeated entities like roads or buildings.
Q3. Can Flyweight be combined with other optimization techniques?
- Object pooling to reuse objects efficiently.
- Lazy initialization to delay object creation until absolutely necessary.
- Caching strategies to store and retrieve Flyweight objects more effectively.