在C#里面,我们可以很容易的通过Clone()方法实现原型模式。任何类,只要想支持克隆,必须实现C#中的ICloneable接口。ICloneable接口中有一Clone方法,可以在类中复写实现自定义的克隆方法。克隆的实现方法有两种:浅拷贝(shallow copy)与深拷贝(deep copy)。
(以下摘自:《.NET框架程序设计(修订版)》,李建忠译)浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。
客户(Client)角色:客户类提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个C#接口或抽象类实现。此角色给出所有的具体原型类所需的接口。在C#中,抽象原型角色通常实现了ICloneable接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象原型角色所要求的接口。
下面的程序给出了一个示意性的实现:
//
Prototype pattern -- Structural example
using
System;

//
"Prototype"
abstract
class
Prototype

...
{
// Fields
private string id;

// Constructors
public Prototype( string id )

...{
this.id = id;
}

public string Id

...{

get...{ return id; }
}

// Methods
abstract public Prototype Clone();
}

//
"ConcretePrototype1"
class
ConcretePrototype1 : Prototype

...
{
// Constructors

public ConcretePrototype1( string id ) : base ( id ) ...{}

// Methods
override public Prototype Clone()

...{
// Shallow copy
return (Prototype)this.MemberwiseClone();
}
}

//
"ConcretePrototype2"
class
ConcretePrototype2 : Prototype

...
{
// Constructors

public ConcretePrototype2( string id ) : base ( id ) ...{}

// Methods
override public Prototype Clone()

...{
// Shallow copy
return (Prototype)this.MemberwiseClone();
}
}


/**/
/**/
/**/
/// <summary>
/// Client test
/// </summary>
class
Client

...
{
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 );
}
}
这个例子实现了一个浅拷贝。其中MemberwiseClone()方法是Object类的一个受保护方法,实现了对象的浅拷贝。如果希望实现一个深拷贝,应该实现ICloneable接口,并自己编写ICloneable的Clone接口方法。
2.原型模式的第二种形式是带原型管理器的原型模式
客户(Client)角色:客户端类向原型管理器提出创建对象的请求。
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个C#接口或抽象类实现。此角色给出所有的具体原型类所需的接口。在C#中,抽象原型角色通常实现了ICloneable接口。
具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。
原型管理器(Prototype Manager)角色:创建具体原型类的对象,并记录每一个被创建的对象。
//
Prototype pattern -- Real World example
using
System;
using
System.Collections;

//
"Prototype"
abstract
class
ColorPrototype

...
{
// Methods
public abstract ColorPrototype Clone();
}

//
"ConcretePrototype"
class
Color : ColorPrototype

...
{
// Fields
private int red, green, blue;

// Constructors
public Color( int red, int green, int blue)

...{
this.red = red;
this.green = green;
this.blue = blue;
}

// Methods
public override ColorPrototype Clone()

...{
// Creates a 'shallow copy'
return (ColorPrototype) this.MemberwiseClone();
}

public void Display()

...{
Console.WriteLine( "RGB values are: {0},{1},{2}",
red, green, blue );
}
}

//
Prototype manager
class
ColorManager

...
{
// Fields
Hashtable colors = new Hashtable();

// Indexers
public ColorPrototype this[ string name ]

...{

get...{ return (ColorPrototype)colors[ name ]; }

set...{ colors.Add( name, value ); }
}
}


/**/
/**/
/**/
/// <summary>
/// PrototypeApp test
/// </summary>
class
PrototypeApp

...
{
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 uses selected colors
string colorName = "red";
Color c1 = (Color)colormanager[ colorName ].Clone();
c1.Display();

colorName = "peace";
Color c2 = (Color)colormanager[ colorName ].Clone();
c2.Display();

colorName = "flame";
Color c3 = (Color)colormanager[ colorName ].Clone();
c3.Display();
}
}
浅拷贝
using
System;

class
ShallowCopy : ICloneable

...
{

public int[] v = ...{1,2,3};

public Object Clone()

...{
return this.MemberwiseClone();
}

public void Display()

...{
foreach(int i in v)
Console.Write( i + ", ");
Console.WriteLine();
}
}

class
Client

...
{
public static void Main()

...{
ShallowCopy sc1 = new ShallowCopy();
ShallowCopy sc2 = (ShallowCopy)sc1.Clone();
sc1.v[0] = 9;

sc1.Display();
sc2.Display();
}
}
深拷贝
using
System;

class
DeepCopy : ICloneable

...
{

public int[] v = ...{1,2,3};

// 默认构造函数
public DeepCopy()

...{
}

// 供Clone方法调用的私有构造函数
private DeepCopy(int[] v)

...{
this.v = (int[])v.Clone();
}

public Object Clone()

...{
// 构造一个新的DeepCopy对象,构造参数为
// 原有对象中使用的 v
return new DeepCopy(this.v);
}

public void Display()

...{
foreach(int i in v)
Console.Write( i + ", ");
Console.WriteLine();
}
}

class
Client

...
{
public static void Main()

...{
DeepCopy dc1 = new DeepCopy();
DeepCopy dc2 = (DeepCopy)dc1.Clone();
dc1.v[0] = 9;

dc1.Display();
dc2.Display();
}
}
Prototype模式的优点与缺点
Prototype模式的优点包括
1、Prototype模式允许动态增加或减少产品类。由于创建产品类实例的方法是产批类内部具有的,因此增加新产品对整个结构没有影响。
2、Prototype模式提供了简化的创建结构。工厂方法模式常常需要有一个与产品类等级结构相同的等级结构,而Prototype模式就不需要这样。
3、Portotype模式具有给一个应用软件动态加载新功能的能力。由于Prototype的独立性较高,可以很容易动态加载新功能而不影响老系统。
4、产品类不需要非得有任何事先确定的等级结构,因为Prototype模式适用于任何的等级结构。
Prototype模式的缺点:
Prototype模式的最主要缺点就是每一个类必须配备一个克隆方法。而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事。