C#編程中使用設(shè)計(jì)模式中的原型模式的實(shí)例講解
一、引言
在軟件系統(tǒng)中,當(dāng)創(chuàng)建一個(gè)類的實(shí)例的過程很昂貴或很復(fù)雜,并且我們需要?jiǎng)?chuàng)建多個(gè)這樣類的實(shí)例時(shí),如果我們用new操作符去創(chuàng)建這樣的類實(shí)例,這未免會(huì)增加創(chuàng)建類的復(fù)雜度和耗費(fèi)更多的內(nèi)存空間,因?yàn)檫@樣在內(nèi)存中分配了多個(gè)一樣的類實(shí)例對(duì)象,然后如果采用工廠模式來創(chuàng)建這樣的系統(tǒng)的話,隨著產(chǎn)品類的不斷增加,導(dǎo)致子類的數(shù)量不斷增多,反而增加了系統(tǒng)復(fù)雜程度,所以在這里使用工廠模式來封裝類創(chuàng)建過程并不合適,然而原型模式可以很好地解決這個(gè)問題,因?yàn)槊總€(gè)類實(shí)例都是相同的,當(dāng)我們需要多個(gè)相同的類實(shí)例時(shí),沒必要每次都使用new運(yùn)算符去創(chuàng)建相同的類實(shí)例對(duì)象,此時(shí)我們一般思路就是想——只創(chuàng)建一個(gè)類實(shí)例對(duì)象,如果后面需要更多這樣的實(shí)例,可以通過對(duì)原來對(duì)象拷貝一份來完成創(chuàng)建,這樣在內(nèi)存中不需要?jiǎng)?chuàng)建多個(gè)相同的類實(shí)例,從而減少內(nèi)存的消耗和達(dá)到類實(shí)例的復(fù)用。 然而這個(gè)思路正是原型模式的實(shí)現(xiàn)方式。下面就具體介紹下設(shè)計(jì)模式中的原型設(shè)計(jì)模式。
二、原型模式的詳細(xì)介紹
我們來看一個(gè)入學(xué)考試場(chǎng)景實(shí)例
基對(duì)象(一般為接口,抽象類):考試題(樣卷)
原型模式的復(fù)職克隆:根據(jù)需要印刷考卷,這里的考卷都是復(fù)制考試題樣卷
客戶端:學(xué)生答卷,同一套試卷,學(xué)生做題不可能一模一樣
類圖:
接口:試卷樣例代碼
/// <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 知道設(shè)計(jì)模式嗎
{
get;
set;
}
string 設(shè)計(jì)模式有幾種
{
get;
set;
}
string 你知道那些
{
get;
set;
}
SelectTest 附加題
{
get;
set;
}
Test Test
{
get;
set;
}
Test Test1
{
get;
set;
}
}
復(fù)制克隆:復(fù)印機(jī)
/// <summary>
/// 繼承Itest接口
/// </summary>
public class Test : Itest
{
private string one;
private string two;
private string three;
private SelectTest other=new SelectTest();
public string 知道設(shè)計(jì)模式嗎
{
get
{
return this.one;
}
set
{
this.one = value;
}
}
public string 設(shè)計(jì)模式有幾種
{
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()
{
//克隆當(dāng)前類
return (Itest)this.MemberwiseClone();
}
#endregion
}
客戶端,發(fā)卷做題
static void Main()
{
//印刷試卷
Itest test = new Test();
//復(fù)制樣本試卷
Itest test1 = test.Clone();
//考生1
test.設(shè)計(jì)模式有幾種 = "23";
test.附加題.你老婆多大 = "18";
//考生2
test1.設(shè)計(jì)模式有幾種 = "24";
test1.附加題.你老婆多大 = "20";
//顯示考生答卷內(nèi)容
Console.WriteLine("test設(shè)計(jì)模式有幾種:" + test.設(shè)計(jì)模式有幾種); //23
Console.WriteLine("test附加題.你老婆多大:" + test.附加題.你老婆多大); //20
Console.WriteLine("test1設(shè)計(jì)模式有幾種:" + test1.設(shè)計(jì)模式有幾種); //24
Console.WriteLine("test1附加題.你老婆多大:" + test1.附加題.你老婆多大); //20
Console.ReadKey();
}
注意:這里兩個(gè)人答得不一樣,為什么附加題中,老婆年齡都為20?
這里涉及到深拷貝,淺拷貝問題,值類型是放在棧上的,拷貝之后,會(huì)自會(huì)在站上重新add一個(gè),而class屬于引用類型,拷貝之后,棧上重新分配啦一個(gè)指針,可指針卻指向同一個(gè)位置的資源。淺拷貝,只拷貝值類型,深拷貝,引用類型也拷貝復(fù)制。
解決方案:
public Itest Clone()
{
//克隆當(dāng)前類
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 知道設(shè)計(jì)模式嗎
{
get;
set;
}
string 設(shè)計(jì)模式有幾種
{
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 知道設(shè)計(jì)模式嗎
{
get
{
return this.one;
}
set
{
this.one = value;
}
}
public string 設(shè)計(jì)模式有幾種
{
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);
}
}
這就是對(duì)原型模式的運(yùn)用。介紹完原型模式的實(shí)現(xiàn)代碼之后,下面看下原型模式的類圖,通過類圖來理清原型模式實(shí)現(xiàn)中類之間的關(guān)系。具體類圖如下:
三、原型模式的優(yōu)缺點(diǎn)
原型模式的優(yōu)點(diǎn)有:
原型模式向客戶隱藏了創(chuàng)建新實(shí)例的復(fù)雜性
原型模式允許動(dòng)態(tài)增加或較少產(chǎn)品類。
原型模式簡(jiǎn)化了實(shí)例的創(chuàng)建結(jié)構(gòu),工廠方法模式需要有一個(gè)與產(chǎn)品類等級(jí)結(jié)構(gòu)相同的等級(jí)結(jié)構(gòu),而原型模式不需要這樣。
產(chǎn)品類不需要事先確定產(chǎn)品的等級(jí)結(jié)構(gòu),因?yàn)樵湍J竭m用于任何的等級(jí)結(jié)構(gòu)
原型模式的缺點(diǎn)有:
每個(gè)類必須配備一個(gè)克隆方法
配備克隆方法需要對(duì)類的功能進(jìn)行通盤考慮,這對(duì)于全新的類不是很難,但對(duì)于已有的類不一定很容易,特別當(dāng)一個(gè)類引用不支持串行化的間接對(duì)象,或者引用含有循環(huán)結(jié)構(gòu)的時(shí)候。
四、.NET中原型模式的實(shí)現(xiàn)
在.NET中可以很容易地通過實(shí)現(xiàn)ICloneable接口(這個(gè)接口就是原型,提供克隆方法,相當(dāng)于與上面代碼中MonkeyKingPrototype抽象類)中Clone()方法來實(shí)現(xiàn)原型模式,如果我們想我們自定義的類具有克隆的功能,首先定義類繼承與ICloneable接口并實(shí)現(xiàn)Clone方法。在.NET中實(shí)現(xiàn)了原型模式的類如下圖所示(圖中只截取了部分,可以用Reflector反編譯工具進(jìn)行查看):
上一篇:C#委托與事件初探
欄 目:C#教程
下一篇:C#實(shí)現(xiàn)PDF文件添加圖片背景
本文標(biāo)題:C#編程中使用設(shè)計(jì)模式中的原型模式的實(shí)例講解
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/6693.html
您可能感興趣的文章
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并打開的方法
- 01-10C#實(shí)現(xiàn)Winform中打開網(wǎng)頁頁面的方法
- 01-10C#實(shí)現(xiàn)由四周向中心縮小的窗體退出特效
- 01-10Extjs4如何處理后臺(tái)json數(shù)據(jù)中日期和時(shí)間
- 01-10C#編程實(shí)現(xiàn)自定義熱鍵的方法
- 01-10C#使用Dispose模式實(shí)現(xiàn)手動(dòng)對(duì)資源的釋放
- 01-10C#3.0使用EventLog類寫Windows事件日志的方法
- 01-10C#中DataGridView常用操作實(shí)例小結(jié)
- 01-10C#編程獲取資源文件中圖片的方法
- 01-10C#使用windows服務(wù)開啟應(yīng)用程序的方法


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 04-02jquery與jsp,用jquery
- 01-10delphi制作wav文件的方法


