前言
點選檢視:設計模式系列
原型模式(Prototype)
理解:原型模式屬於建立型模式,與工廠,單件,生成器模式有相似點,就是建立物件,而原型模式最大的特點就是對一個基類物件進行克隆複製建立出模型一樣的副本,進行操作。
舉例:
即將開學啦,就來個入學考試吧
基物件(一般為介面,抽象類):考試題(樣卷)
原型模式的復職克隆:根據需要印刷考卷,這裡的考卷都是複製考試題樣卷
客戶端:學生答卷,同一套試卷,學生做題不可能一模一樣
類圖:
介面:試卷樣例程式碼
/// <summary> /// 選答題 /// </summary> public class SelectTest { private string other; public string 你老婆多大 { get { return this.other; } set { this.other = value; } } } /// <summary> /// 面試題 /// </summary> public interface Itest { Itest Clone(); string 知道設計模式嗎 { get; set; } string 設計模式有幾種 { get; set; } string 你知道那些 { get; set; } SelectTest 附加題 { get; set; } Test Test { get; set; } Test Test1 { get; set; } }
複製克隆:影印機
/// <summary> /// 繼承Itest介面 /// </summary> public class Test : Itest { private string one; private string two; private string three; private SelectTest other=new SelectTest(); public string 知道設計模式嗎 { get { return this.one; } set { this.one = value; } } public string 設計模式有幾種 { get { return this.two; } set { this.two = value; } } public string 你知道那些 { get { return this.three; } set { this.three = value; } } public SelectTest 附加題 { get { return this.other; } set { this.other = value; } } #region IColorDemo 成員 public Itest Clone() { //克隆當前類 return (Itest)this.MemberwiseClone(); } #endregion }
客戶端,髮捲做題
static void Main() { //印刷試卷 Itest test = new Test(); //複製樣本試卷 Itest test1 = test.Clone(); //考生1 test.設計模式有幾種 = "23"; test.附加題.你老婆多大 = "18"; //考生2 test1.設計模式有幾種 = "24"; test1.附加題.你老婆多大 = "20"; //顯示考生答卷內容 Console.WriteLine("test設計模式有幾種:" + test.設計模式有幾種); //23 Console.WriteLine("test附加題.你老婆多大:" + test.附加題.你老婆多大); //20 Console.WriteLine("test1設計模式有幾種:" + test1.設計模式有幾種); //24 Console.WriteLine("test1附加題.你老婆多大:" + test1.附加題.你老婆多大); //20 Console.ReadKey(); }
注意:這裡兩個人答得不一樣,為什麼附加題中,老婆年齡都為20?
這裡涉及到深拷貝,淺拷貝問題,值型別是放在棧上的,拷貝之後,會自會在站上重新add一個,而class屬於引用型別,拷貝之後,棧上重新分配啦一個指標,可指標卻指向同一個位置的資源。淺拷貝,只拷貝值型別,深拷貝,引用型別也拷貝複製。
解決方案:
public Itest Clone() { //克隆當前類 Itest itst= (Itest)this.MemberwiseClone(); SelectTest st = new SelectTest(); st.你老婆多大 = this.other.你老婆多大; itst.附加題 = st; return itst; }
使用序列化解決
/// <summary> /// 選答題 /// </summary> [Serializable] public class SelectTest { private string other; public string 你老婆多大 { get { return this.other; } set { this.other = value; } } } /// <summary> /// 面試題 /// </summary> public interface Itest { Itest Clone(); string 知道設計模式嗎 { get; set; } string 設計模式有幾種 { get; set; } string 你知道那些 { get; set; } SelectTest 附加題 { get; set; } } /// <summary> /// 繼承Itest介面 /// </summary> [Serializable] public class Test : Itest { private string one; private string two; private string three; private SelectTest other=new SelectTest(); public string 知道設計模式嗎 { get { return this.one; } set { this.one = value; } } public string 設計模式有幾種 { get { return this.two; } set { this.two = value; } } public string 你知道那些 { get { return this.three; } set { this.three = value; } } public SelectTest 附加題 { get { return this.other; } set { this.other = value; } } public Itest Clone() { SerializableHelper SerializableHelper = new 原型模式.SerializableHelper(); string target = SerializableHelper.Serializable(this); return SerializableHelper.Derializable<Itest>(target); } }
public class SerializableHelper { public string Serializable(object target) { using (MemoryStream stream = new MemoryStream()) { new BinaryFormatter().Serialize(stream, target); return Convert.ToBase64String(stream.ToArray()); } } public object Derializable(string target) { byte[] targetArray = Convert.FromBase64String(target); using (MemoryStream stream = new MemoryStream(targetArray)) { return new BinaryFormatter().Deserialize(stream); } } public T Derializable<T>(string target) { return (T)Derializable(target); } }
答卷結束,總結原型模式
原型模式的用處很多,比如現在比較流行的orm技術,修改,編輯前一個原型帶資料的,克隆原型樣例然後對其複製,然後再讓這兩個編輯前後的物件做對比,如果相同就不修改,不同則生成sql語句經行update。原型模式的身形還是很常見的,因為他建立新物件方便快捷,而且可在執行時根據需要通過克隆來新增和去除他們,也可在程式執行是根據情況來修改類內部的資料,而且執行時無需建立類就能夠得到你想要的新生物件。
歡迎加入部落格左上方群,交流探討,設計模式,資料庫,c#.net,資料結構。