C語言程式設計中使用設計模式中的原型模式的講解

一、引言

C語言程式設計中使用設計模式中的原型模式的講解

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

二、原型模式的詳細介紹

我們來看一個入學考試場景例項

基物件(一般為介面,抽象類):考試題(樣卷)

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

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

類圖:

介面:試卷樣例程式碼

///

/// 選答題 ///

public class SelectTest { private string other; public string 你老婆多大 { get { return r; } set { r = value; } } } ///

/// 面試題 ///

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; } }

複製克隆:影印機

///

/// 繼承Itest介面 ///

public class Test : Itest { private string one; private string two; private string three; private SelectTest other=new SelectTest(); public string 知道設計模式嗎 { get { return ; } set { = value; } } public string 設計模式有幾種 { get { return ; } set { = value; } } public string 你知道那些 { get { return e; } set { e = value; } } public SelectTest 附加題 { get { return r; } set { r = value; } } #region IColorDemo 成員 public Itest Clone() { //克隆當前類 return (Itest)erwiseClone(); } #endregion }

客戶端,髮捲做題

static void Main() { //印刷試卷 Itest test = new Test(); //複製樣本試卷 Itest test1 = e(); //考生1 test.設計模式有幾種 = "23"; test.附加題.你老婆多大 = "18"; //考生2 test1.設計模式有幾種 = "24"; test1.附加題.你老婆多大 = "20"; //顯示考生答卷內容 eLine("test設計模式有幾種:" + test.設計模式有幾種); //23 eLine("test附加題.你老婆多大:" + test.附加題.你老婆多大); //20 eLine("test1設計模式有幾種:" + test1.設計模式有幾種); //24 eLine("test1附加題.你老婆多大:" + test1.附加題.你老婆多大); //20 Key(); }

注意:這裡兩個人答得不一樣,為什麼附加題中,老婆年齡都為20?

這裡涉及到深拷貝,淺拷貝問題,值型別是放在棧上的,拷貝之後,會自會在站上重新add一個,而class屬於引用型別,拷貝之後,棧上重新分配啦一個指標,可指標卻指向同一個位置的資源。淺拷貝,只拷貝值型別,深拷貝,引用型別也拷貝複製。

解決方案:

public Itest Clone() { //克隆當前類 Itest itst= (Itest)erwiseClone(); SelectTest st = new SelectTest(); st.你老婆多大 = r.你老婆多大; itst.附加題 = st; return itst; }

使用序列化解決

///

/// 選答題 ///

[Serializable] public class SelectTest { private string other; public string 你老婆多大 { get { return r; } set { r = value; } } } ///

/// 面試題 ///

public interface Itest { Itest Clone(); string 知道設計模式嗎 { get; set; } string 設計模式有幾種 { get; set; } string 你知道那些 { get; set; } SelectTest 附加題 { get; set; } } ///

/// 繼承Itest介面 ///

public class Test : Itest { private string one; private string two; private string three; private SelectTest other=new SelectTest(); public string 知道設計模式嗎 { get { return ; } set { = value; } } public string 設計模式有幾種 { get { return ; } set { = value; } } public string 你知道那些 { get { return e; } set { e = value; } } public SelectTest 附加題 { get { return r; } set { r = value; } } public Itest Clone() { SerializableHelper SerializableHelper = new 原型模式alizableHelper(); string target = alizable(this); return alizable

(target); } } public class SerializableHelper { public string Serializable(object target) { using (MemoryStream stream = new MemoryStream()) { new BinaryFormatter()alize(stream, target); return se64String(ray()); } } public object Derializable(string target) { byte[] targetArray = Base64String(target); using (MemoryStream stream = new MemoryStream(targetArray)) { return new BinaryFormatter()rialize(stream); } } public T Derializable(string target) { return (T)Derializable(target); } }

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

三、原型模式的優缺點

原型模式的優點有:

原型模式向客戶隱藏了建立新例項的複雜性

原型模式允許動態增加或較少產品類。

原型模式簡化了例項的建立結構,工廠方法模式需要有一個與產品類等級結構相同的等級結構,而原型模式不需要這樣。

產品類不需要事先確定產品的等級結構,因為原型模式適用於任何的等級結構

原型模式的缺點有:

每個類必須配備一個克隆方法

配備克隆方法需要對類的功能進行通盤考慮,這對於全新的類不是很難,但對於已有的類不一定很容易,特別當一個類引用不支援序列化的間接物件,或者引用含有迴圈結構的時候。

四、中原型模式的實現

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