原型模式就是從一個對象再創建另一個可定製的對象,而不需要知道任何創建的細節。 原型模式本身是比較簡單的,不過其中牽涉到淺複製和深複製的實現,下麵使用.Net自帶的方法和介面分別實現淺複製和深複製: MemberwiseClone方法實現的是淺複製,即如果欄位是值類型,則對該欄位執行逐位複製,如果欄位 ...
原型模式就是從一個對象再創建另一個可定製的對象,而不需要知道任何創建的細節。
原型模式本身是比較簡單的,不過其中牽涉到淺複製和深複製的實現,下麵使用.Net自帶的方法和介面分別實現淺複製和深複製:
public class WorkExperience : ICloneable { public string workDate; public string experience; #region ICloneable 成員 public object Clone() { //淺複製 return this.MemberwiseClone(); } #endregion }
MemberwiseClone方法實現的是淺複製,即如果欄位是值類型,則對該欄位執行逐位複製,如果欄位是引用類型,則複製引用但不複製引用的對象,因此,原是對象及其複本引用的是同一對象。不過,經過測試發現,對string類型的執行的複製與值類型是相同的,修改新變數中string的值不會影響原變數的值測試如下:
WorkExperience we = new WorkExperience(); we.workDate="today"; we.experience="test";
//輸出為work experience: today, test Console.WriteLine("work experience: {0},{1}", we.workDate, e.experience); WorkExperience we2 = (WorkExperience)we.Clone(); we2.experience = "test2"; we2.workDate = "tomorrow";
//輸出為work experience: tomorrow,test2 Console.WriteLine("work experience: {0},{1}", we2.workDate, e2.experience);
//輸出為work experience: today, test
Console.WriteLine("work experience: {0},{1}", we.workDate, we.experience);
下麵演示如何進行深複製和淺複製:
public class Resume : ICloneable { public string name;
//引用類型,需要區分深複製和淺複製 public WorkExperience workExperience; public Resume(string name) { this.name = name; workExperience = new WorkExperience(); } public void SetExperience(string workDate, string experience) { workExperience.workDate=workDate; workExperience.experience=experience; } public void Show() { Console.WriteLine("name : {0}",name); Console.WriteLine("work experience: {0},{1}",workExperience.workDate,workExperience.experience); } /// <summary> /// 提供一個私有構造函數,供複製方法使用,以便複製WorkExperience的數據 /// </summary> /// <param name="workExperience"></param> private Resume(WorkExperience workExperience) { this.workExperience = (WorkExperience)workExperience.Clone(); } #region ICloneable 成員 /// <summary> ///深複製,實例化一個新的對象 /// </summary> /// <returns></returns> public object Clone() { Resume newResume = new Resume(this.workExperience); newResume.name = this.name; return newResume; } /// <summary> /// 淺複製 /// </summary> /// <returns></returns> public object Copy() { return this.MemberwiseClone(); } #endregion }
上例中Clone和Copy分別實現了深複製和淺複製,測試如下:
Resume myResume = new Resume("Kelly");
myResume.SetExperience("2004-2008", "University");
myResume.Show();
//使用淺複製,更改WorkExperience,則被覆制對象也被更改
Resume newResume = (Resume)myResume.Copy();
newResume.SetExperience("2008-2012", "Master Degree");
newResume.name = "Mike";
myResume.Show();
//使用深複製,更改WorkExperience,被覆制對象不會被更改
Resume newResume2 = (Resume)myResume.Clone();
newResume2.SetExperience("2012-now", "Company");
newResume2.name = "Jack";
myResume.Show();
運行結果為:
name : Kelly
work experience: 2004-2008,University
name : Kelly
work experience: 2008-2012,Master Degree
name : Kelly
work experience: 2008-2012,Master Degree
可以看出,name由於是string類型,所以始終不會被修改,work experience是引用類型,在第一次做淺複製後被修改,第二次做深複製後沒有被修改。
一般在初始化信息不發生變化的情況下,克隆是最好的辦法,這即隱藏了對象創建的細節,又對性能有很大的提高。