C#編程中使用設計模式中的原型模式的實例講解
一、引言
在軟件系統(tǒng)中,當創(chuàng)建一個類的實例的過程很昂貴或很復雜,并且我們需要創(chuàng)建多個這樣類的實例時,如果我們用new操作符去創(chuàng)建這樣的類實例,這未免會增加創(chuàng)建類的復雜度和耗費更多的內存空間,因為這樣在內存中分配了多個一樣的類實例對象,然后如果采用工廠模式來創(chuàng)建這樣的系統(tǒng)的話,隨著產(chǎn)品類的不斷增加,導致子類的數(shù)量不斷增多,反而增加了系統(tǒng)復雜程度,所以在這里使用工廠模式來封裝類創(chuàng)建過程并不合適,然而原型模式可以很好地解決這個問題,因為每個類實例都是相同的,當我們需要多個相同的類實例時,沒必要每次都使用new運算符去創(chuàng)建相同的類實例對象,此時我們一般思路就是想——只創(chuàng)建一個類實例對象,如果后面需要更多這樣的實例,可以通過對原來對象拷貝一份來完成創(chuàng)建,這樣在內存中不需要創(chuàng)建多個相同的類實例,從而減少內存的消耗和達到類實例的復用。 然而這個思路正是原型模式的實現(xiàn)方式。下面就具體介紹下設計模式中的原型設計模式。
二、原型模式的詳細介紹
我們來看一個入學考試場景實例
基對象(一般為接口,抽象類):考試題(樣卷)
原型模式的復職克?。焊鶕?jù)需要印刷考卷,這里的考卷都是復制考試題樣卷
客戶端:學生答卷,同一套試卷,學生做題不可能一模一樣
類圖:
接口:試卷樣例代碼
/// <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; } }
復制克?。簭陀C
/// <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 }
客戶端,發(fā)卷做題
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> 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); } }
這就是對原型模式的運用。介紹完原型模式的實現(xiàn)代碼之后,下面看下原型模式的類圖,通過類圖來理清原型模式實現(xiàn)中類之間的關系。具體類圖如下:
三、原型模式的優(yōu)缺點
原型模式的優(yōu)點有:
原型模式向客戶隱藏了創(chuàng)建新實例的復雜性
原型模式允許動態(tài)增加或較少產(chǎn)品類。
原型模式簡化了實例的創(chuàng)建結構,工廠方法模式需要有一個與產(chǎn)品類等級結構相同的等級結構,而原型模式不需要這樣。
產(chǎn)品類不需要事先確定產(chǎn)品的等級結構,因為原型模式適用于任何的等級結構
原型模式的缺點有:
每個類必須配備一個克隆方法
配備克隆方法需要對類的功能進行通盤考慮,這對于全新的類不是很難,但對于已有的類不一定很容易,特別當一個類引用不支持串行化的間接對象,或者引用含有循環(huán)結構的時候。
四、.NET中原型模式的實現(xiàn)
在.NET中可以很容易地通過實現(xiàn)ICloneable接口(這個接口就是原型,提供克隆方法,相當于與上面代碼中MonkeyKingPrototype抽象類)中Clone()方法來實現(xiàn)原型模式,如果我們想我們自定義的類具有克隆的功能,首先定義類繼承與ICloneable接口并實現(xiàn)Clone方法。在.NET中實現(xiàn)了原型模式的類如下圖所示(圖中只截取了部分,可以用Reflector反編譯工具進行查看):
相關文章
C#值類型、引用類型中的Equals和==的區(qū)別淺析
這篇文章主要介紹了C#值類型、引用類型中的Equals和==的區(qū)別淺析,本文分別對C#值類型和引用類型中的Equals和==做了講解和給出了實例,需要的朋友可以參考下2015-01-01C#使用ToUpper()與ToLower()方法將字符串進行大小寫轉換的方法
這篇文章主要介紹了C#使用ToUpper()與ToLower()方法將字符串進行大小寫轉換的方法,實例分析了C#大小寫轉換的相關技巧,需要的朋友可以參考下2015-04-04