The Prototype design pattern specifies the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.
C# code examples of the Prototype design pattern is provided in 3 forms:
A visualization of the classes and objects participating in this pattern.
The classes and objects participating in this pattern include:
ColorPrototype
)
Color
)
ColorManager
)
This structural code demonstrates the Prototype pattern in which new objects are created by copying pre-existing objects (prototypes) of the same class.
using System;
namespace Prototype.Structural
{
/// <summary>
/// Prototype Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Create two instances and clone each
ConcretePrototype1 p1 = new ConcretePrototype1("I");
ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
Console.WriteLine("Cloned: {0}", c1.Id);
ConcretePrototype2 p2 = new ConcretePrototype2("II");
ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
Console.WriteLine("Cloned: {0}", c2.Id);
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Prototype' abstract class
/// </summary>
public abstract class Prototype
{
string id;
// Constructor
public Prototype(string id)
{
this.id = id;
}
// Gets id
public string Id
{
get { return id; }
}
public abstract Prototype Clone();
}
/// <summary>
/// A 'ConcretePrototype' class
/// </summary>
public class ConcretePrototype1 : Prototype
{
// Constructor
public ConcretePrototype1(string id)
: base(id)
{
}
// Returns a shallow copy
public override Prototype Clone()
{
return (Prototype)this.MemberwiseClone();
}
}
/// <summary>
/// A 'ConcretePrototype' class
/// </summary>
public class ConcretePrototype2 : Prototype
{
// Constructor
public ConcretePrototype2(string id)
: base(id)
{
}
// Returns a shallow copy
public override Prototype Clone()
{
return (Prototype)this.MemberwiseClone();
}
}
}
This real-world code demonstrates the Prototype pattern in which new Color objects are created by copying pre-existing, user-defined Colors of the same type.
using System;
using System.Collections.Generic;
namespace Prototype.RealWorld
{
/// <summary>
/// Prototype Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
ColorManager colormanager = new ColorManager();
// Initialize with standard colors
colormanager["red"] = new Color(255, 0, 0);
colormanager["green"] = new Color(0, 255, 0);
colormanager["blue"] = new Color(0, 0, 255);
// User adds personalized colors
colormanager["angry"] = new Color(255, 54, 0);
colormanager["peace"] = new Color(128, 211, 128);
colormanager["flame"] = new Color(211, 34, 20);
// User clones selected colors
Color color1 = colormanager["red"].Clone() as Color;
Color color2 = colormanager["peace"].Clone() as Color;
Color color3 = colormanager["flame"].Clone() as Color;
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Prototype' abstract class
/// </summary>
public abstract class ColorPrototype
{
public abstract ColorPrototype Clone();
}
/// <summary>
/// The 'ConcretePrototype' class
/// </summary>
public class Color : ColorPrototype
{
int red;
int green;
int blue;
// Constructor
public Color(int red, int green, int blue)
{
this.red = red;
this.green = green;
this.blue = blue;
}
// Create a shallow copy
public override ColorPrototype Clone()
{
Console.WriteLine(
"Cloning color RGB: {0,3},{1,3},{2,3}",
red, green, blue);
return this.MemberwiseClone() as ColorPrototype;
}
}
/// <summary>
/// Prototype manager
/// </summary>
public class ColorManager
{
private Dictionary<string, ColorPrototype> colors =
new Dictionary<string, ColorPrototype>();
// Indexer
public ColorPrototype this[string key]
{
get { return colors[key]; }
set { colors.Add(key, value); }
}
}
}
The .NET optimized code demonstrates the same code as above but uses
more modern C# and .NET features.
Here is an elegant C# Prototyp solution.
namespace Prototype.NetOptimized;
using static System.Console;
using System.Text.Json;
using System.Collections.Generic;
/// <summary>
/// Prototype Design Pattern
/// </summary>
public class Program
{
public static void Main()
{
var manager = new ColorManager();
// Initialize with standard colors
manager[ColorType.Red] = new Color { Red = 255, Blue = 0, Green = 0 };
manager[ColorType.Green] = new Color { Red = 0, Blue = 255, Green = 0 };
manager[ColorType.Blue] = new Color { Red = 0, Blue = 0, Green = 255 };
// User adds personalized colors
manager[ColorType.Angry] = new Color { Red = 255, Blue = 54, Green = 0 };
manager[ColorType.Peace] = new Color { Red = 128, Blue = 211, Green = 128 };
manager[ColorType.Flame] = new Color { Red = 211, Blue = 34, Green = 20 };
// User uses selected colors
_ = manager[ColorType.Red].Clone();
_ = manager[ColorType.Peace].Clone();
_ = manager[ColorType.Flame].Clone(false); // Deep Copy
// Wait for user
ReadKey();
}
}
/// <summary>
/// ICloneable is not supported in .NET Core
/// </summary>
public interface ICloneableObject
{
object Clone();
}
/// <summary>
/// The 'ConcretePrototype' class
/// </summary>
public class Color : ICloneableObject
{
public byte Red { get; set; }
public byte Green { get; set; }
public byte Blue { get; set; }
// Returns a shallow or a deep copy
public object? Clone(bool shallow)
{
return shallow ? Clone() : DeepCopy();
}
// Creates a shallow copy
public object Clone()
{
WriteLine(
"Shallow copy of color RGB: {0,3},{1,3},{2,3}",
Red, Green, Blue);
return MemberwiseClone();
}
// Creates a deep copy
public object? DeepCopy()
{
// use serialized to create a deep copy
var serialized = JsonSerializer.Serialize(this);
var copy = JsonSerializer.Deserialize<Color>(serialized);
if (copy is not null)
{
WriteLine(
"*Deep* copy of color RGB: {0,3},{1,3},{2,3}",
(copy as Color).Red, (copy as Color).Green, (copy as Color).Blue
);
}
return copy;
}
}
/// <summary>
/// Type-safe prototype manager
/// </summary>
public record ColorManager
{
private readonly Dictionary<ColorType, Color> colors = [];
// Gets or sets color
public Color this[ColorType type]
{
get => colors[type];
set => colors.Add(type, value);
}
}
/// <summary>
/// Color type enumerations
/// </summary>
public enum ColorType
{
Red,
Green,
Blue,
Angry,
Peace,
Flame
}