程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#編程中使用設計模式中的原型模式的實例講解

C#編程中使用設計模式中的原型模式的實例講解

編輯:關於C語言

一、引言
在軟件系統中,當創建一個類的實例的過程很昂貴或很復雜,並且我們需要創建多個這樣類的實例時,如果我們用new操作符去創建這樣的類實例,這未免會增加創建類的復雜度和耗費更多的內存空間,因為這樣在內存中分配了多個一樣的類實例對象,然後如果采用工廠模式來創建這樣的系統的話,隨著產品類的不斷增加,導致子類的數量不斷增多,反而增加了系統復雜程度,所以在這裡使用工廠模式來封裝類創建過程並不合適,然而原型模式可以很好地解決這個問題,因為每個類實例都是相同的,當我們需要多個相同的類實例時,沒必要每次都使用new運算符去創建相同的類實例對象,此時我們一般思路就是想——只創建一個類實例對象,如果後面需要更多這樣的實例,可以通過對原來對象拷貝一份來完成創建,這樣在內存中不需要創建多個相同的類實例,從而減少內存的消耗和達到類實例的復用。 然而這個思路正是原型模式的實現方式。下面就具體介紹下設計模式中的原型設計模式。

二、原型模式的詳細介紹
我們來看一個入學考試場景實例

基對象(一般為接口,抽象類):考試題(樣卷)

原型模式的復職克隆:根據需要印刷考卷,這裡的考卷都是復制考試題樣卷

客戶端:學生答卷,同一套試卷,學生做題不可能一模一樣

類圖:

2016217153039715.png (784×574)

接口:試卷樣例代碼

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 /// <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; } }


復制克隆:復印機

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 /// <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 }

客戶端,發卷做題

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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屬於引用類型,拷貝之後,棧上重新分配啦一個指針,可指針卻指向同一個位置的資源。淺拷貝,只拷貝值類型,深拷貝,引用類型也拷貝復制。

解決方案:

? 1 2 3 4 5 6 7 8 9 10 public Itest Clone() { //克隆當前類 Itest itst= (Itest)this.MemberwiseClone(); SelectTest st = new SelectTest(); st.你老婆多大 = this.other.你老婆多大; itst.附加題 = st; return itst; }

使用序列化解決

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 /// <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> 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); } }

這就是對原型模式的運用。介紹完原型模式的實現代碼之後,下面看下原型模式的類圖,通過類圖來理清原型模式實現中類之間的關系。具體類圖如下:

2016217153142427.png (758×262)

三、原型模式的優缺點

原型模式的優點有

原型模式向客戶隱藏了創建新實例的復雜性
原型模式允許動態增加或較少產品類。
原型模式簡化了實例的創建結構,工廠方法模式需要有一個與產品類等級結構相同的等級結構,而原型模式不需要這樣。
產品類不需要事先確定產品的等級結構,因為原型模式適用於任何的等級結構

原型模式的缺點有:
每個類必須配備一個克隆方法
配備克隆方法需要對類的功能進行通盤考慮,這對於全新的類不是很難,但對於已有的類不一定很容易,特別當一個類引用不支持串行化的間接對象,或者引用含有循環結構的時候。


四、.Net中原型模式的實現
在.NET中可以很容易地通過實現ICloneable接口(這個接口就是原型,提供克隆方法,相當於與上面代碼中MonkeyKingPrototype抽象類)中Clone()方法來實現原型模式,如果我們想我們自定義的類具有克隆的功能,首先定義類繼承與ICloneable接口並實現Clone方法。在.Net中實現了原型模式的類如下圖所示(圖中只截取了部分,可以用Reflector反編譯工具進行查看):

2016217153206825.png (378×557)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved