设计模式(六)原型模式
原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需知道任何创建的细节。
1 // 原型类 2 abstract class Prototype 3 { 4 private string id; 5 6 public Prototype(string id) 7 { 8 this.id = id; 9 } 10 11 public string Id 12 { 13 get { return id; } 14 } 15 // 抽象类关键就是有这样一个 Clone 方法 16 public abstract Prototype Clone(); 17 } 18 19 // 具体原型类 20 class ConcretePrototype1 : Prototype 21 { 22 public ConcretePrototype1(string id) : base(id) 23 { 24 } 25 // 创建当前对象的浅表副本。方法是创建一个新对象,然后将当前对象的非静态字段复制到该对象。如果字段是值类型的,则对该字段执行逐位复制。 26 // 如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其副本引用同一对象。 27 public override Prototype Clone() 28 { 29 return (Prototype)this.MemberwiseClone(); 30 } 31 } 32 33 // 客户端代码 34 Static void Main(string[] args) 35 { 36 ConcretePrototype1 p1 = new ConcretePrototype1( "I" ); 37 38 // 克隆类 ConcretePrototype1 的对象 p1 就能得到新的实例 c1 39 ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone(); 40 41 Console.WriteLine("Cloned: {0}", c1.Id ); 42 Console.Read(); 43 }
对于 .NET 而言,原型抽象类 Prototype 是用不着的。因为 .NET 在 System 命名空间中提供了 ICloneable 接口,其中就是唯一的一个方法 Clone(),只需要实现这个接口就可以完成原型模式了。
一般在初始化的信息不发生变化的情况下,克隆是最好的方法。克隆不用重新初始化对象,而是动态地获得对象运行时的状态。这样既隐藏了对象创建的细节,又提高了性能。
浅复制
MemberwiseClone() 方法是这样:如果字段是值类型的,则对该字段执行逐位复制;如果字段是引用类型,则复制引用但不复制引用的对象;因此,原始对象及其复本引用同一对象。浅复制使得被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深复制
深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。深复制要深入很多层,需要事先就考虑好,而且要当心出现循环引用的问题。
【例】简历的深复制实现

实现代码
1 // 工作经历类,实现 ICloneable 接口 2 class WorkExperence : ICloneable 3 { 4 private string workDate; 5 public string WorkDate 6 { 7 get { return workDate; } 8 set { workDate = value; } 9 } 10 11 private string company; 12 public string Company 13 { 14 get { return company; } 15 set { company = value; } 16 } 17 18 public Object Clone() 19 { 20 return (Object)this.MemberwiseClone(); 21 } 22 } 23 24 // 简历类 25 class Resume : ICloneable 26 { 27 private string name; 28 private string sex; 29 private string age; 30 31 private WorkExperience work; 32 33 public Resume(string name) 34 { 35 this.name = name; 36 work = new WorkExperience(); 37 } 38 // 提供 Clone 方法调用的私有构造函数,以便克隆 “工作经历” 的数据 39 public Resume(WorkExperience work) 40 { 41 this.work = (WorkExperience)work.Clone(); 42 } 43 // 设置个人信息 44 public void SetPersonalInfo(string sex, string age) 45 { 46 this.sex = sex; 47 this.age = age; 48 } 49 // 设置工作经历 50 public void SetWorkExperience(string workDate, string company) 51 { 52 work.WorkDate = workDate; 53 work.Company = company; 54 } 55 // 显示 56 public void Display() 57 { 58 Console.WriteLine("{0} {1} {2}", name, sex, age); 59 Console.WriteLine("工作经历:{0} {1} ", work.WorkDate, work.Company ); 60 } 61 // 62 public Object Clone() 63 { 64 Resume obj = new Resume(this.work); 65 obj.name = this.name; 66 obj.sex = this.sex; 67 obj.age = this.age; 68 return obj; 69 } 70 71 }
【总结】
在一些特定场合,会经常涉及深复制或浅复制。比如说,数据集对象 DataSet,它就有 Clone() 方法和 Copy() 方法,Clone() 方法用来复制 DataSet 的结构,但不复制 DataSet 的数据,实现了原型模式的浅复制。Copy() 方法不但复制结构,也复制数据,其实就是实现了原型模式的深复制。

浙公网安备 33010602011771号