原型模式(Prototype),用原型实例指定建立对象的种类,而且经过拷贝这些原型建立新的对象。javascript
简单说来原型模式就是从一个对象再建立另一个可定制的对象,并且不需知道任何建立的细节。html
原型模式UML图:java
原型模式的基本代码结构:git
namespace ConsoleApplication1 { abstract class Prototype { private string id; public Prototype(string id) { this.id = id; } public string Id { get { return id; } } public abstract Prototype Clone(); //抽象类的关键就是要有这样一个克隆方法 } //具体原型类 class ConcretePrototype1 : Prototype { public ConcretePrototype1(string id): base(id) { } public override Prototype Clone() { return (Prototype)this.MemberwiseClone(); //建立当前对象的浅表副本。方法是建立一个新对象,而后将当前对象的非静态字段复制到该新对象。 //若是字段是值类型,则对该字段执行逐位复制,若是字段是引用类型,则复制引用但不复制引用的对象 //所以,原始对象及其副本引用赞成对象 } } class Program { static void Main(string[] args) { ConcretePrototype1 p1 = new ConcretePrototype1("I"); ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone(); //原型模式建立对象 Console.WriteLine("Cloned:{0}",c1.Id); //输出 Cloned:I Console.ReadKey(); } } }
原型模式的做用:咱们知道每new一次对象,都须要执行一次构造函数,若是构造函数的执行时间很长,那么屡次的执行初始化操做就比较低效。一半在初始化的信息不发生变化的状况下,克隆是最好的办法,这既隐藏了对象建立的细节,又能对性能是大大的提升。不用从新初始化对象,而是动态地得到对象运行时的状态。设计模式
在使用原型模式中,有必要注意浅复制与深复制的概念。ide
对于上面的原型结构示例代码:咱们知道若是字段是值类型的,则对该字段执行逐位复制,若是字段是引用类型的,则复制引用但不复制引用的对象;所以,原始对象及其副本引用赞成对象。函数
浅复制:被复制对象的全部变量都含有与原来对象相同的值,而全部的对其余对象的引用都仍然指向原来的对象。也就是说,浅复制复制出来的对象,若是里面含有引用类型的数据,则浅复制复制出来的对象与原对象是同一个,由于仅复制引用地址嘛。post
深复制:当执行复制时,被复制的对象含有引用类型对象的变量时,引用类型的变量对象也从新复制一份,即复制出来的引用对象与原类中的对象不是指向同一个地址。性能
所以,在使用原型模式时必需要分析好,是该浅复制仍是深复制。学习
回到《大话设计模式中的示例》 简历的原型实现:
namespace ConsoleApplication1 { class WorkExperience : ICloneable //主要,要让工做经历实现ICloneable { private string workDate; public string WorkDate { get { return workDate; } set { workDate = value; } } private string company; public string Company { get { return company; } set { company = value; } } public Object Clone() { return (Object)this.MemberwiseClone(); } } //简历类 class Resume : ICloneable { private string name; private string sex; private string age; private WorkExperience work; public Resume(string Name) { this.name = Name; work = new WorkExperience(); } private Resume(WorkExperience Work) { this.work = (WorkExperience)Work.Clone(); //注意深复制必需要添加此段代码,提供Clone方法调用的私有构造函数以便克制工做经历 } //设置我的信息 public void SetPersonnalInfo(string Sex, string Age) { this.sex = Sex; this.age = Age; } //设置工做经历 public void SetWorkExperience(string workDate, string company) { work.WorkDate = workDate; work.Company = company; } //显示 public void Display() { Console.WriteLine("{0} {1} {2}",name,sex,age); Console.WriteLine("工做经历:{0} {1}", work.WorkDate, work.Company); } public Object Clone() { Resume obj = new Resume(this.work); obj.name = this.name; obj.sex = this.sex; obj.age = this.age; return obj; } } class Program { static void Main(string[] args) { Resume a = new Resume("大鸟"); a.SetPersonnalInfo("男","29"); a.SetWorkExperience("1998-2000","微软"); Resume b = (Resume)a.Clone(); b.SetWorkExperience("2000-2004","google"); Resume c = (Resume)a.Clone(); c.SetPersonnalInfo("男","24"); c.SetWorkExperience("1998-2004","苹果"); a.Display(); b.Display(); c.Display(); Console.ReadKey(); } } }