Prototype¶
- Prototype
- UML class diagram
- Participants
- Structural code in C# .{10}
- Real-world code in C# .{10}
- .NET Optimized code in C# .{10}
Summary: Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.
Frequency of use: Medium
UML class diagram¶
Participants¶
The classes and objects participating in this pattern are:
- Prototype (
ColorPrototype
) - declares an interface for cloning itself
- ConcretePrototype (
Color
) - implements an operation for cloning itself
- Client (
ColorManager
) - creates a new object by asking a prototype to clone itself
Structural code in C# .{10}¶
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 DoFactory.GangOfFour.Prototype.Structural {
/// <summary>
/// MainApp startup class for Structural
/// Prototype Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main() {
// 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>
abstract class Prototype
{
private 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>
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>
class ConcretePrototype2: Prototype
{
// Constructor
public ConcretePrototype2(string id) : base(id) {}
// Returns a shallow copy
public override Prototype Clone() {
return (Prototype) this.MemberwiseClone();
}
}
}
Output¶
Real-world code in C# .{10}¶
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 DoFactory.GangOfFour.Prototype.RealWorld {
/// <summary>
/// MainApp startup class for Real-World
/// Prototype Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main() {
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>
abstract class ColorPrototype
{
public abstract ColorPrototype Clone();
}
/// <summary>
/// The 'ConcretePrototype' class
/// </summary>
class Color: ColorPrototype
{
private int _red;
private int _green;
private 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>
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);
}
}
}
}
Output¶
.NET Optimized code in C# .{10}¶
using System;
using System.Runtime.Remoting;
namespace DoFactory.GangOfFour.Proxy.NETOptimized
{
/// <summary>
/// MainApp startup class for .NET optimized
/// Proxy Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
// Create math proxy
var proxy = new MathProxy();
// Do the math
Console.WriteLine("4 + 2 = " + proxy.Add(4, 2));
Console.WriteLine("4 - 2 = " + proxy.Sub(4, 2));
Console.WriteLine("4 * 2 = " + proxy.Mul(4, 2));
Console.WriteLine("4 / 2 = " + proxy.Div(4, 2));
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Subject' interface
/// </summary>
public interface IMath
{
double Add(double x, double y);
double Sub(double x, double y);
double Mul(double x, double y);
double Div(double x, double y);
}
/// <summary>
/// The 'RealSubject' class
/// </summary>
class Math : MarshalByRefObject, IMath
{
public double Add(double x, double y) { return x + y; }
public double Sub(double x, double y) { return x - y; }
public double Mul(double x, double y) { return x * y; }
public double Div(double x, double y) { return x / y; }
}
/// <summary>
/// The remote 'Proxy Object' class
/// </summary>
class MathProxy : IMath
{
private Math _math;
// Constructor
public MathProxy()
{
// Create Math instance in a different AppDomain
var ad = AppDomain.CreateDomain("MathDomain", null, null);
var o = ad.CreateInstance(
"DoFactory.GangOfFour.Proxy.NETOptimized",
"DoFactory.GangOfFour.Proxy.NETOptimized.Math");
_math = (Math)o.Unwrap();
}
public double Add(double x, double y)
{
return _math.Add(x, y);
}
public double Sub(double x, double y)
{
return _math.Sub(x, y);
}
public double Mul(double x, double y)
{
return _math.Mul(x, y);
}
public double Div(double x, double y)
{
return _math.Div(x, y);
}
}
}