Skip to content

Prototype

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

alt

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

Cloned: I
Cloned: II

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

Cloning color RGB: 255,  0,  0
Cloning color RGB: 128,211,128
Cloning color RGB: 211, 34, 20

.NET Optimized code in C# .{10}

alt

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);
        }
    }
}