原型模式(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(); } } }