Prototype - Design Pattern
Software Architecture Simplified
Objective 🎯
Allow to create an object from cloning another object (Prototype), to hide the complexity of making new instances and to avoid costly operations.
Notes 📝
• When 2 objects have the same reference it means that they are sharing the same space in memory and any change in one object will reflect in the other.
• Normal Copy process preserves the reference of the original object including the objects inside it.
• Shallow Copy process does not preserve the reference of the original object but keep the reference of the objects inside it.
• Deep Copy process does not preserve the reference of the original object or the reference of the objects inside it.
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 📐
Participants 🔗
• Prototype:
- Declares an interface for cloning itself
• ConcretePrototype:
- Implements an operation for cloning itself
• Client:
- Creates new object by asking a prototype object to clone itself
Sample Code 🎮
Structural Example 🏛️
public static class PrototypeStructural
{
public static void Execute()
{
ConcretePrototype1 lConcretePrototype1 = new ConcretePrototype1("1");
ConcretePrototype1 lCloneConcretePrototype = (ConcretePrototype1)lConcretePrototype1.Clone();
Console.WriteLine($"Cloned {lConcretePrototype1.GetType().Name}");
ConcretePrototype2 lConcretePrototype2 = new ConcretePrototype2("2");
ConcretePrototype2 lCloneConcretePrototype2 = (ConcretePrototype2)lConcretePrototype2.Clone();
Console.WriteLine($"Cloned {lCloneConcretePrototype2.GetType().Name}");
}
}
public abstract class Prototype
{
public string _Id { get; set; }
public Prototype(string prId)
{
_Id = prId;
}
public abstract Prototype Clone();
}
public class ConcretePrototype1 : Prototype
{
public ConcretePrototype1(string prId)
: base(prId) { }
public override Prototype Clone()
{
return (Prototype)this.MemberwiseClone();
}
}
public class ConcretePrototype2 : Prototype
{
public ConcretePrototype2(string prId)
: base(prId) { }
public override Prototype Clone()
{
return (Prototype)this.MemberwiseClone();
}
}
Output
Real-world Example 🔥
public static class PrototypePractical
{
public static void Execute()
{
ShapeHelper lShapeHelper = new ShapeHelper();
lShapeHelper.CreateShapes("Square", 2);
lShapeHelper.CreateShapes("Circle", 3);
lShapeHelper.CreateShapes("Triangle", 4);
Console.WriteLine($"\n\rCreated {lShapeHelper._Shapes.Count} objects in total");
}
}
public class ShapeHelper
{
public List<Shape> _Shapes = new List<Shape>();
public void CreateShapes(string prType, int prQuantity)
{
Shape lOriginalShape = null;
switch (prType)
{
case ("Circle"): lOriginalShape = new Circle("#1"); break;
case ("Square"): lOriginalShape = new Square("#1"); break;
case ("Triangle"): lOriginalShape = new Triangle("#1"); break;
default: break;
}
if (lOriginalShape != null)
{
Console.WriteLine($"• Creating {prQuantity} {lOriginalShape.GetType().Name}s...");
Console.WriteLine($" Created object {lOriginalShape.GetType().Name} - Id: {lOriginalShape._Id}");
_Shapes.Add(lOriginalShape);
for (int i = 1; i < prQuantity; i++)
{
_Shapes.Add(lOriginalShape.Clone());
Console.WriteLine($" Clonned object {lOriginalShape.GetType().Name} - Id: {lOriginalShape._Id}");
}
}
}
}
public abstract class Shape
{
public string _Id { get; set; }
public string _Type { get; set; }
public Shape(string prId, string prType)
{
_Id = prId;
_Type = prType;
}
public virtual Shape Clone()
{
// To "Clone" an object can be done either by using Shallow Copy or Deep Copy approach
// In the below example Shallow Copy approach is used
return (Shape)this.MemberwiseClone();
}
}
public class Circle : Shape
{
public Circle(string prId)
: base(prId, "Circle") { }
}
public class Square : Shape
{
public Square(string prId)
: base(prId, "Square") { }
}
public class Triangle : Shape
{
public Triangle(string prId)
: base(prId, "Triangle") { }
}
Output