前言
點擊查看:設計模式系列
原型模式(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,數據結構。
