一、原型模式介绍:
原型模式用一个原型对象来指明所要创建的对象类型,然后用复制这个原型对象的方法来创建出更多的同类型对象。
二、应用背景:
当创建一个类的实例的过程很复杂,并且我们需要创建多个这样类的实例时,如果我们用new去创建这样的类实例,会增加创建类的复杂度和耗费更多的内存空间,因为这样在内存中分配了多个一样的类实例对象;如果采用工厂模式来创建这样的系统的话,随着产品类的不断增加,导致子类的数量不断增多,反而增加了系统复杂程度;然而原型模式可以很好地解决这个问题,因为每个类实例都是相同的,当我们需要多个相同的类实例时,没必要每次都使用new去创建相同的类实例对象,我们只需创建一个类实例对象,如果后面需要更多这样的实例,可以通过对原来对象拷贝一份来完成创建,这样在内存中不需要创建多个相同的类实例,从而减少内存的消耗和达到类实例的复用。
二、情景例子:
生物体细胞分裂就是一个很好的原型模式例子,一个细胞有丝分裂成两个相同的细胞。
三、相关代码:
1、创建细胞原型抽象父类:
/// <summary> /// 细胞原型抽象父类 /// </summary> public abstract class CellProtoType { //细胞编号 public int id { get; set; } //细胞名称 public string name { get; set; } public CellProtoType(int ID, string Name) { this.id = ID; this.name = Name; } //克隆方法,即细胞分裂 public abstract CellProtoType Clone(); }
2、创建具体细胞类:
//具体原型类 public class Cells : CellProtoType { public Cells(int ID, string Name) : base(ID, Name) { } /// <summary> /// 浅拷贝 /// </summary> /// <returns></returns> public override CellProtoType Clone() { // 调用MemberwiseClone方法实现的是浅拷贝 return (CellProtoType)this.MemberwiseClone(); } }
3、调用
//创建细胞原型 CellProtoType cellprototype = new Cells(10086, "造血干细胞"); //细胞分裂一次 CellProtoType cell1 = cellprototype.Clone() as Cells; Console.WriteLine("{0}====={1}", cell1.id, cell1.name); //再分裂一次 CellProtoType cell2 = cellprototype.Clone() as Cells; Console.WriteLine("{0}====={1}", cell1.id, cell2.name); Console.ReadKey();
四、拷贝形式:
可以看出上面代码实现的是浅拷贝的形式,什么是浅拷贝什么是深拷贝呢?
浅拷贝是指当对象的字段值被拷贝时,字段引用的对象不会被拷贝。例如,如果一个对象有一个指向字符串的字段,并且我们对该对象做了一个浅拷贝,那么这两个对象将引用同一个字符串。执行浅拷贝创建的新对象与原来对象共享成员,改变一个对象,另外一个对象的成员也会改变。
深拷贝是对对象实例中字段引用的对象也进行拷贝,如果一个对象有一个指向字符串的字段,并且我们对该对象进行了深拷贝的话,那么我们将创建一个新对象和一个新的字符串,新的对象将引用新的字符串。执行深拷贝创建的新对象和原来对象不会共享任何东西,改变一个对象对另外一个对象没有任何影响。
另附上利用xml序列化和反序列化深拷贝的形式:
public T DeepCopy<T>(T obj) { object retval; using (MemoryStream ms = new MemoryStream()) { XmlSerializer xml = new XmlSerializer(typeof(T)); xml.Serialize(ms, obj); ms.Seek(0, SeekOrigin.Begin); retval = xml.Deserialize(ms); ms.Close(); } return (T)retval; }
五、总结:
优点:
- 原型模式向客户隐藏了创建新实例的复杂性
- 原型模式允许动态增加或较少产品类。
- 原型模式简化了实例的创建结构,工厂方法模式需要有一个与产品类等级结构相同的等级结构,而原型模式不需要这样。
- 产品类不需要事先确定产品的等级结构,因为原型模式适用于任何的等级结构
缺点:
- 每个类必须配备一个克隆方法
- 配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。