存在目地:通过一个原型实例来指明所要创建的对象类型,并且用拷贝这个原型实例的办法创建出更多的同类型实例对象。
应用实例:细胞分裂,孙大圣的三根汗毛……
应用场合:避免创建一个与产品类层次平行的工厂类层次
简单实现:
using System;
// 抽象原型角色,具体原型角色的接口
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();
}
// 具体原型1,实际被复制的对象
class ConcretePrototype1 : Prototype
{
// Constructors
public ConcretePrototype1( string id ) : base ( id ) {}
// Methods
override public Prototype Clone()
{
// 实现浅拷贝(当对象的字段值被拷贝时,字段引用的对象不会被拷贝)
return (Prototype)this.MemberwiseClone();
}
}
// 具体原型2
class ConcretePrototype2 : Prototype
{
// Constructors
public ConcretePrototype2( string id ) : base ( id ) {}
// Methods
override public Prototype Clone()
{
// Shallow copy
return (Prototype)this.MemberwiseClone();
}
}
// 客户端调用
class Client
{
public static void Main( string[] args )
{
// 创建具体原型实例p1
ConcretePrototype1 p1 = new ConcretePrototype1( "I" );
// 克隆p1创建实例c1
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 );
}
}
引入原型模式的本质在于利用已有的一个原型对象,快速的生成和原型对象一样的实例。注意Object类包括了MemberwiseClone()方法,这个方法被所有的对象继承。
带原型管理器的实现方式:
// 在原型管理器中存储用户预先定义的颜色原型,客户通过原型管理器克隆颜色对象
using System;
using System.Collections;
// 抽象原型角色
abstract class ColorPrototype
{
// Methods
public abstract ColorPrototype Clone();
}
//具体原型
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 );
}
}
// 原型管理器角色,创建具体原型类的对象,并记录每一个被创建的对象。
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 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();
}
}
浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么两个对象将引用同一个字符串。而深拷贝是对对象实例中字段引用的对象也进行拷贝的一种方式,所以如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个深拷贝的话,我们将创建一个新的对象和一个新的字符串--新对象将引用新字符串。需要注意的是执行深拷贝后,原来的对象和新创建的对象不会共享任何东西;改变一个对象对另外一个对象没有任何影响。
参考资料:
Erich Gamma《设计模式可复用面向对象软件的基础》