程序設(shè)計(jì)方法學(xué)23種設(shè)計(jì)模式_第1頁(yè)
程序設(shè)計(jì)方法學(xué)23種設(shè)計(jì)模式_第2頁(yè)
程序設(shè)計(jì)方法學(xué)23種設(shè)計(jì)模式_第3頁(yè)
程序設(shè)計(jì)方法學(xué)23種設(shè)計(jì)模式_第4頁(yè)
程序設(shè)計(jì)方法學(xué)23種設(shè)計(jì)模式_第5頁(yè)
已閱讀5頁(yè),還剩86頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

(1)單例模式

說(shuō)到單例模式,大家第一反應(yīng)應(yīng)該就是——什么是單例模式?,從“單例”字面意思上理解為——一個(gè)類(lèi)只有

一個(gè)實(shí)例,所以單例模式也就是保證一個(gè)類(lèi)只有一個(gè)實(shí)例的一種實(shí)現(xiàn)方法罷了(設(shè)計(jì)模式其實(shí)就是幫助我們解決

實(shí)際開(kāi)發(fā)過(guò)程中的方法,該方法是為了降低對(duì)象之間的耦合度,然而解決方法有很多種,所以前人就總結(jié)了一些

常用的解決方法為書(shū)籍,從而把這本書(shū)就稱(chēng)為設(shè)計(jì)模式),下面給出單例模式的一個(gè)官方定義:確保一個(gè)類(lèi)只有一

個(gè)實(shí)例,并提供一個(gè)全局訪問(wèn)點(diǎn)。為了幫助大家更好地理解單例模式,大家可以結(jié)合下面的類(lèi)圖來(lái)進(jìn)行理解,以及

后面也會(huì)剖析單例模式的實(shí)現(xiàn)思路:

Singleton

-uniqueinstance:Singleton

單例模式:確保一個(gè)類(lèi)只有一個(gè)實(shí)例,、

并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)-Singleton()

+Getlnstance():Singleton

了解完了一些關(guān)于單例模式的基本概念之后,下面就為大家剖析單例模式的實(shí)現(xiàn)思路的,因?yàn)樵谖易约簩W(xué)習(xí)

單例模式的時(shí)候,咋一看單例模式的實(shí)現(xiàn)代碼確實(shí)很簡(jiǎn)單,也很容易看懂,但是我還是覺(jué)得它很陌生(這個(gè)可能

是看的少的,或者自己在寫(xiě)代碼中也用的少的緣故),而且心里總會(huì)這樣一個(gè)疑問(wèn)一一為什么前人會(huì)這樣去實(shí)現(xiàn)

單例模式的呢?他們是如何思考的呢?后面經(jīng)過(guò)自己的琢磨也就慢慢理清楚單例模式的實(shí)現(xiàn)思路了,并且此時(shí)也

不再覺(jué)得單例模式陌生了,下面就分享我的一個(gè)剖析過(guò)程的:

我們從單例模式的概念(確保一個(gè)類(lèi)只有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn))入手,可以把概念進(jìn)

行拆分為兩部分:(1)確保一個(gè)類(lèi)只有一個(gè)實(shí)例;(2)提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn);下面通過(guò)采用兩人對(duì)

話(huà)的方式來(lái)幫助大家更快掌握分析思路:

菜鳥(niǎo):怎樣確保一個(gè)類(lèi)只有一個(gè)實(shí)例了?

老鳥(niǎo):那就讓我?guī)湍惴治鱿拢銊?chuàng)建類(lèi)的實(shí)例會(huì)想到用什么方式來(lái)創(chuàng)建的呢?

新手:用new關(guān)鍵字啊,只要new下就創(chuàng)建了該類(lèi)的一個(gè)實(shí)例了,之后就可以使用該類(lèi)的一些

屬性和實(shí)例方法了

老鳥(niǎo):那你想過(guò)為什么可以使用new關(guān)鍵字來(lái)創(chuàng)建類(lèi)的實(shí)例嗎?

菜鳥(niǎo):這個(gè)還有條件的嗎?......,哦,我想起來(lái)了,如果類(lèi)定義私有的構(gòu)造函數(shù)就不能在外界

通過(guò)new創(chuàng)建實(shí)例了(注:有些初學(xué)者就會(huì)問(wèn),有時(shí)候我并沒(méi)有在類(lèi)中定義構(gòu)造函數(shù)為什么也可以使

用new來(lái)創(chuàng)建對(duì)象,那是因?yàn)榫幾g器在背后做了手腳了,當(dāng)編譯器看到我們類(lèi)中沒(méi)有定義構(gòu)造函數(shù),

此時(shí)編譯器會(huì)幫我們生成一個(gè)公有的無(wú)參構(gòu)造函數(shù))

老鳥(niǎo):不錯(cuò),回答的很對(duì),這樣你的疑惑就得到解答了啊

菜鳥(niǎo):那我要在哪里創(chuàng)建類(lèi)的實(shí)例了?

老鳥(niǎo):你傻啊,當(dāng)然是在類(lèi)里面創(chuàng)建了(注:這樣定義私有構(gòu)造函數(shù)就是上面的一個(gè)思考過(guò)程的,

要?jiǎng)?chuàng)建實(shí)例,自然就要有一個(gè)變量來(lái)保存該實(shí)例把,所以就有了私有變量的聲明,但是實(shí)現(xiàn)中是定義靜

態(tài)私有變量,朋友們有沒(méi)有想過(guò)——這里為什么定義為靜態(tài)的呢?對(duì)于這個(gè)疑問(wèn)的解釋為:每個(gè)線(xiàn)程都

有自己的線(xiàn)程棧,定義為靜態(tài)主要是為了在多線(xiàn)程確保類(lèi)有一個(gè)實(shí)例)

菜鳥(niǎo):哦,現(xiàn)在完全明白了,但是我還有另一個(gè)疑問(wèn)——現(xiàn)在類(lèi)實(shí)例創(chuàng)建在類(lèi)內(nèi)部,那外界如何獲

得該的一個(gè)實(shí)例來(lái)使用它了?

老鳥(niǎo):這個(gè),你可以定義一個(gè)公有方法或者屬性來(lái)把該類(lèi)的實(shí)例公開(kāi)出去了(注:這樣就有了公有

方法的定義了,該方法就是提供方法問(wèn)類(lèi)的全局訪問(wèn)點(diǎn))

通過(guò)上面的分析,相信大家也就很容易寫(xiě)出單例模式的實(shí)現(xiàn)代碼了,下面就看看具體的實(shí)現(xiàn)代碼(看完之后

你會(huì)驚訝道:真是這樣的!):

III單例模式的實(shí)現(xiàn)

publicclassSingleton

(

//定義一個(gè)靜態(tài)變量來(lái)保存類(lèi)的實(shí)例

privatestaticSingletonuniqueinstance;

//定義私有構(gòu)造函數(shù),使外界不能創(chuàng)建該類(lèi)實(shí)例

privateSingleton(){}

III定義公有方法提供一個(gè)全局訪問(wèn)點(diǎn),同時(shí)你也可以定義公有屬性來(lái)提供全局訪問(wèn)點(diǎn)

publicstaticSingletonGetlnstance()

{

//如果類(lèi)的實(shí)例不存在則創(chuàng)建,否則直接返回

if(uniqueinstance==null)

(

uniqueinstance=newSingleton();

)

returnuniqueinstance;

)

)

上面的單例模式的實(shí)現(xiàn)在單線(xiàn)程下確實(shí)是完美的,然而在多線(xiàn)程的情況下會(huì)得到多個(gè)Singleton實(shí)

例,因?yàn)樵趦蓚€(gè)線(xiàn)程同時(shí)運(yùn)行Getlnstance方法時(shí),此時(shí)兩個(gè)線(xiàn)程判斷(uniqueinstance==null)這個(gè)條

件時(shí)都返回真,此時(shí)兩個(gè)線(xiàn)程就都會(huì)創(chuàng)建Singleton的實(shí)例,這樣就違背了我們單例模式初衷了,

既然上面的實(shí)現(xiàn)會(huì)運(yùn)行多個(gè)線(xiàn)程執(zhí)行,那我們對(duì)于多線(xiàn)程的解決方案自然就是使Getlnstance方法

在同一時(shí)間只運(yùn)行一個(gè)線(xiàn)程運(yùn)行就好了,也就是我們線(xiàn)程同步的問(wèn)題了(對(duì)于線(xiàn)程同步大家也可以

參考我線(xiàn)程同步的文章),具體的解決多線(xiàn)程的代碼如下:

III單例模式的實(shí)現(xiàn)

publicclassSingleton

//定義一個(gè)靜態(tài)變量來(lái)保存類(lèi)的實(shí)例

privatestaticSingletonuniqueinstance;

//定義一個(gè)標(biāo)識(shí)確保線(xiàn)程同步

privatestaticreadonlyobjectlocker=newobject();

//定義私有構(gòu)造函數(shù),使外界不能創(chuàng)建該類(lèi)實(shí)例

privateSingleton(){}

///定義公有方法提供一個(gè)全局訪問(wèn)點(diǎn),同時(shí)你也可以定義公有屬性來(lái)提供全局訪問(wèn)點(diǎn)

publicstaticSingletonGetlnstancef)

{

//當(dāng)?shù)谝粋€(gè)線(xiàn)程運(yùn)行到這里時(shí),此時(shí)會(huì)對(duì)locker對(duì)象"加鎖",

//當(dāng)?shù)诙€(gè)線(xiàn)程運(yùn)行該方法時(shí),首先檢測(cè)到locker對(duì)象為"加鎖"狀態(tài),該線(xiàn)程就會(huì)

掛起等待第一個(gè)線(xiàn)程解鎖

〃lock語(yǔ)句運(yùn)行完之后(即線(xiàn)程運(yùn)行完之后)會(huì)對(duì)該對(duì)象"解鎖"

lock(locker)

(

//如果類(lèi)的實(shí)例不存在則創(chuàng)建,否則直接返回

if(uniqueinstance==null)

{

uniqueinstance=newSingleton();

)

)

returnuniqueinstance;

)

)

(2)簡(jiǎn)單工廠模式

說(shuō)到簡(jiǎn)單工廠,自然的第一個(gè)疑問(wèn)當(dāng)然就是什么是簡(jiǎn)單工廠模式了?在現(xiàn)實(shí)生活中工廠是負(fù)責(zé)生產(chǎn)產(chǎn)品的,

同樣在設(shè)計(jì)模式中,簡(jiǎn)單工廠模式我們也可以理解為負(fù)責(zé)生產(chǎn)對(duì)象的一個(gè)類(lèi),我們平常編程中,當(dāng)使用“new”關(guān)鍵

字創(chuàng)建一個(gè)對(duì)象時(shí),此時(shí)該類(lèi)就依賴(lài)與這個(gè)對(duì)象,也就是他們之間的耦合度高,當(dāng)需求變化時(shí),我們就不得不去

修改此類(lèi)的源碼,此時(shí)我們可以運(yùn)用面向?qū)ο?00)的很重要的原則去解決這一的問(wèn)題,該原則就是——封裝

改變,既然要封裝改變,自然也就要找到改變的代碼,然后把改變的代碼用類(lèi)來(lái)封裝,這樣的一種思路也就是

我們簡(jiǎn)單工廠模式的實(shí)現(xiàn)方式了。下面通過(guò)一個(gè)現(xiàn)實(shí)生活中的例子來(lái)引出簡(jiǎn)單工廠模式。在外面打工的人,免不

了要經(jīng)常在外面吃飯,當(dāng)然我們也可以自己在家做飯吃,但是自己做飯吃麻煩,因?yàn)橛忠约嘿I(mǎi)菜,然而,出去

吃飯就完全沒(méi)有這些麻煩的,我們只需要到餐館點(diǎn)菜就可以了,買(mǎi)菜的事情就交給餐館做就可以了,這里餐館就

充當(dāng)簡(jiǎn)單工廠的角色,下面讓我們看看現(xiàn)實(shí)生活中的例子用代碼是怎樣來(lái)表現(xiàn)的。自己做飯的情況:

///自己做飯的情況

///沒(méi)有簡(jiǎn)單工廠之前,客戶(hù)想吃什么菜只能自己炒的

publicclassCustomer

(

///燒菜方法

publicstaticFoodCook(stringtype)

(

Foodfood=null;

//客戶(hù)A說(shuō):我想吃西紅柿炒蛋怎么辦?

//客戶(hù)B說(shuō):那你就自己燒啊

//客戶(hù)A說(shuō):好吧,那就自己做吧

if(type.Equals("西紅柿炒蛋”))

food=newTomatoScrambledEggs();

//我又想吃土豆肉絲,這個(gè)還是得自己做

//我覺(jué)得自己做好累哦,如果能有人幫我做就好了?

elseif(type.Equals(〃土豆肉絲”))

food=newShreddedPorkWithPotatoes();

)

returnfood;

}

staticvoidMain(string[]args)

{

//做西紅柿炒蛋

Foodfoodl=Cook(〃西紅柿炒蛋”);

foodl.Print();

Foodfood2=Cook(〃土豆肉絲〃);

food2.Print();

Console.Read();

///菜抽象類(lèi)

publicabstractclassFood

//輸出點(diǎn)了什么菜

publicabstractvoidPrint();

///西紅柿炒雞蛋這道菜

publicclassTomatoScrambledEggs:Food

{

publicoverridevoidPrint()

Console.WriteLine(〃一份西紅柿炒蛋!〃);

)

///土豆肉絲這道菜

publicclassShreddedPorkWithPotatoes:Food

publicoverridevoidPrint()

Console.WriteLine(z,一份土豆肉絲〃);

自己做飯,如果我們想吃別的菜時(shí),此時(shí)就需要去買(mǎi)這種菜和洗菜這些繁瑣的操作,有了餐館(也就是簡(jiǎn)單

工廠)之后,我們就可以把這些操作交給餐館去做,此時(shí)消費(fèi)者(也就是我們)對(duì)菜(也就是具體對(duì)象)的依賴(lài)

關(guān)系從直接變成的間接的,這樣就是實(shí)現(xiàn)了面向?qū)ο蟮牧硪粋€(gè)原則——降低對(duì)象之間的耦合度,下面就具體看看

有了餐館之后的實(shí)現(xiàn)代碼(即簡(jiǎn)單工廠的實(shí)現(xiàn)):

///顧客充當(dāng)客戶(hù)端,負(fù)責(zé)調(diào)用簡(jiǎn)單工廠來(lái)生產(chǎn)對(duì)象

///即客戶(hù)點(diǎn)菜,廚師(相當(dāng)于簡(jiǎn)單工廠)負(fù)責(zé)燒菜(生產(chǎn)的對(duì)象)

classCustomer

{

staticvoidMain(string[]args)

(

//客戶(hù)想點(diǎn)一個(gè)西紅柿炒蛋

Foodfoodl=FoodSimpleFactory.CreateFood("西紅柿炒蛋”);

foodl.Print();

//客戶(hù)想點(diǎn)一個(gè)土豆肉絲

Foodfood2=FoodSimpleFactory.CreateFood(“土豆肉絲”);

food2.Print();

Console.Read();

}

}

///菜抽象類(lèi)

publicabstractclassFood

(

//輸出點(diǎn)了什么菜

publieabstractvoidPrint();

)

///西紅柿炒雞蛋這道菜

publicclassTomatoScrambledEggs:Food

{

publicoverridevoidPrint()

(

Console.WriteLine("一份西紅柿炒蛋!”);

)

)

///土豆肉絲這道菜

publicclassShreddedPorkWithPotatoes:Food

{

publicoverridevoidPrint()

(

Console.WriteLine("一份土豆肉絲“);

)

)

///簡(jiǎn)單工廠類(lèi),負(fù)責(zé)炒菜

publicclassFoodSimpleFactory

{

publicstaticFoodCreateFood(stringtype)

(

Foodfood=null;

if(type.Equals("土豆肉絲”))

(

food=newShreddedPorkWithPotatoes();

)

elseif(type.Equals("西紅柿炒蛋”))

food=newTomatoScrambledEggs();

returnfood;

優(yōu)點(diǎn)與缺點(diǎn)

看完簡(jiǎn)單工廠模式的實(shí)現(xiàn)之后,你和你的小伙伴們肯定會(huì)有這樣的疑惑(因?yàn)槲覍W(xué)習(xí)的時(shí)候也有)——這樣

我們只是把變化移到了工廠類(lèi)中罷了,好像沒(méi)有變化的問(wèn)題,因?yàn)槿绻蛻?hù)想吃其他菜時(shí),此時(shí)我們還是需要修

改工廠類(lèi)中的方法(也就是多加case語(yǔ)句,沒(méi)應(yīng)用簡(jiǎn)單工廠模式之前,修改的是客戶(hù)類(lèi))。我首先要說(shuō):你和

你的小伙伴很對(duì),這個(gè)就是簡(jiǎn)單工廠模式的缺點(diǎn)所在(這個(gè)缺點(diǎn)后面介紹的工廠方法可以很好地解決),然而,

簡(jiǎn)單工廠模式與之前的實(shí)現(xiàn)也有它的優(yōu)點(diǎn):

?簡(jiǎn)單工廠模式解決了客戶(hù)端直接依賴(lài)于具體對(duì)象的問(wèn)題,客戶(hù)端可以消除直接創(chuàng)建對(duì)象的責(zé)任,而僅僅是

消費(fèi)產(chǎn)品。簡(jiǎn)單工廠模式實(shí)現(xiàn)了對(duì)責(zé)任的分割。

?簡(jiǎn)單工廠模式也起到了代碼復(fù)用的作用,因?yàn)橹暗膶?shí)現(xiàn)(自己做飯的情況)中,換了一個(gè)人同樣要去在

自己的類(lèi)中實(shí)現(xiàn)做菜的方法,然后有了簡(jiǎn)單工廠之后,去餐館吃飯的所有人都不用那么麻煩了,只需要負(fù)

責(zé)消費(fèi)就可以了。此時(shí)簡(jiǎn)單工廠的燒菜方法就讓所有客戶(hù)共用了。(同時(shí)這點(diǎn)也是簡(jiǎn)單工廠方法的缺點(diǎn)——

因?yàn)楣S類(lèi)集中了所有產(chǎn)品創(chuàng)建邏輯,一旦不能正常工作,整個(gè)系統(tǒng)都會(huì)受到影響,也沒(méi)什么不好理解的,

就如事物都有兩面性一樣道理)

雖然上面已經(jīng)介紹了簡(jiǎn)單工廠模式的缺點(diǎn),下面還是總結(jié)下簡(jiǎn)單工廠模式的缺點(diǎn):

?工廠類(lèi)集中了所有產(chǎn)品創(chuàng)建邏輯,一旦不能正常工作,整個(gè)系統(tǒng)都會(huì)受到影響(通俗地意思就是:一旦餐

館沒(méi)飯或者關(guān)門(mén)了,很多不愿意做飯的人就沒(méi)飯吃了)

?系統(tǒng)擴(kuò)展困難,一旦添加新產(chǎn)品就不得不修改工廠邏輯,這樣就會(huì)造成工廠邏輯過(guò)于復(fù)雜。

了解了簡(jiǎn)單工廠模式之后的優(yōu)缺點(diǎn)之后,我們之后就可以知道簡(jiǎn)單工廠的應(yīng)用場(chǎng)景了:

?當(dāng)工廠類(lèi)負(fù)責(zé)創(chuàng)建的對(duì)象比較少時(shí)可以考慮使用簡(jiǎn)單工廠模式。

?客戶(hù)如果只知道傳入工廠類(lèi)的參數(shù),對(duì)于如何創(chuàng)建對(duì)象的邏輯不關(guān)心時(shí)可以考慮使用簡(jiǎn)單工廠模式

(3)工廠方法模式

工廠方法模式之所以可以解決簡(jiǎn)單工廠的模式,是因?yàn)樗膶?shí)現(xiàn)把具體產(chǎn)品的創(chuàng)建推遲到子類(lèi)中,此時(shí)工廠

類(lèi)不再負(fù)責(zé)所有產(chǎn)品的創(chuàng)建,而只是給出具體工廠必須實(shí)現(xiàn)的接口,這樣工廠方法模式就可以允許系統(tǒng)不修改工

廠類(lèi)邏輯的情況下來(lái)添加新產(chǎn)品,這樣也就克服了簡(jiǎn)單工廠模式中缺點(diǎn)。下面看下工廠模式的具體實(shí)現(xiàn)代碼(這

里還是以簡(jiǎn)單工廠模式中點(diǎn)菜的例子來(lái)實(shí)現(xiàn)):

namespace設(shè)計(jì)模式之工廠方法模式

(

///菜抽象類(lèi)

publicabstractclassFood

(

//輸出點(diǎn)了什么菜

publieabstractvoidPrint();

}

///西紅柿炒雞蛋這道菜

publicclassTomatoScrambledEggs:Food

{

publicoverridevoidPrint()

(

Console.WriteLine("西紅柿炒蛋好了!");

)

}

///土豆肉絲這道菜

publicclassShreddedPorkWithPotatoes:Food

{

publicoverridevoidPrint()

(

Console.WriteLine("土豆肉絲好了“);

)

)

///抽象工廠類(lèi)

publicabstractclassCreator

{

//工廠方法

publicabstractFoodCreateFoddFactory();

)

///西紅柿炒蛋工廠類(lèi)

publicclassTomatoScrambledEggsFactory:Creator

(

///負(fù)責(zé)創(chuàng)建西紅柿炒蛋這道菜

publicoverrideFoodCreateFoddFactory()

(

returnnewTomatoScrambledEggs();

)

///土豆肉絲工廠類(lèi)

publicclassShreddedPorkWithPotatoesFactory:Creator

(

///負(fù)責(zé)創(chuàng)建土豆肉絲這道菜

publieoverrideFoodCreateFoddFactory()

(

returnnewShreddedPorkWithPotatoes();

)

)

///客戶(hù)端調(diào)用

classClient

(

staticvoidMain(string[]args)

(

//初始化做菜的兩個(gè)工廠O

CreatorshreddedPorkWithPotatoesFactory=new

ShreddedPorkWithPotatoesFactory();

CreatortomatoScrambledEggsFactory=newTomatoScrambledEggsFactory();

//開(kāi)始做西紅柿炒蛋

FoodtomatoScrambleEggs=tomatoScrambledEggsFactory.CreateFoddFactory();

tomatoScrambleEggs.Print();

〃開(kāi)始做土豆肉絲

FoodShreddedPorkWithPotatoes=

shreddedPorkWithPotatoesFactory.CreateFoddFactory();

ShreddedPorkWithPotatoes.Print();

Console.ReadO;

)

)

)

使用工廠方法實(shí)現(xiàn)的系統(tǒng),如果系統(tǒng)需要添加新產(chǎn)品時(shí),我們可以利用多態(tài)性來(lái)完成系統(tǒng)的擴(kuò)展,對(duì)于抽象

工廠類(lèi)和具體工廠中的代碼都不需要做任何改動(dòng)。例如,我們我們還想點(diǎn)一個(gè)“肉末茄子”,此時(shí)我們只需要定義

一個(gè)肉末茄子具體工廠類(lèi)和肉末茄子類(lèi)就可以。而不用像簡(jiǎn)單工廠模式中那樣去修改工廠類(lèi)中的實(shí)現(xiàn)(具體指添

加case語(yǔ)句)。具體代碼為:

///肉末茄子這道菜

publicclassMincedMeatEggplant:Food

(

///重寫(xiě)抽象類(lèi)中的方法

publicoverridevoidPrint()

(

Console.WriteLine("肉末茄子好了“);

)

)

///肉末茄子工廠類(lèi),負(fù)責(zé)創(chuàng)建肉末茄子這道菜

publicclassMincedMeatEggplantFactory:Creator

(

///負(fù)責(zé)創(chuàng)建肉末茄子這道菜

publicoverrideFoodCreateFoddFactory()

returnnewMincedMeatEggplant();

Ill客戶(hù)端調(diào)用

classClient

staticvoidMain(string[]args)

(

//如果客戶(hù)又想點(diǎn)肉末茄子了

//再另外初始化一個(gè)肉末茄子工廠

CreatorminceMeatEggplantFactor=newMincedMeatEggplantFactory();

//利用肉末茄子工廠來(lái)創(chuàng)建肉末茄子這道菜

FoodminceMeatEggplant=minceMeatEggplantFactor.CreateFoddFactory();

minceMeatEggplant.Print();

Console.Read();

)

)

在工廠方法模式中,工廠類(lèi)與具體產(chǎn)品類(lèi)具有平行的等級(jí)結(jié)構(gòu),它們之間是一一對(duì)應(yīng)的。針對(duì)UML圖的解釋如

下:

Creator類(lèi):充當(dāng)抽象工廠角色,任何具體工廠都必須繼承該抽象類(lèi)

TomatoScrambledEggsFactory和ShreddedPorkWithPotatoesFactory類(lèi):充當(dāng)具體工廠角色,用來(lái)

創(chuàng)建具體產(chǎn)品

Food類(lèi):充當(dāng)抽象產(chǎn)品角色,具體產(chǎn)品的抽象類(lèi)。任何具體產(chǎn)品都應(yīng)該繼承該類(lèi)

TomatoScrambledEggs和ShreddedPorkWithPotatoes類(lèi):充當(dāng)具體產(chǎn)品角色,實(shí)現(xiàn)抽象產(chǎn)品類(lèi)對(duì)定

義的抽象方法,由具體工廠類(lèi)創(chuàng)建,它們之間有一一對(duì)應(yīng)的關(guān)系。

(4)抽象工廠模式

下面就以生活中“絕味”連鎖店的例子來(lái)實(shí)現(xiàn)一個(gè)抽象工廠模式。例如,絕味鴨脖想在江西南昌和上海開(kāi)分

店,但是由于當(dāng)?shù)厝说目谖恫灰粯樱谀喜乃薪^味的東西會(huì)做的辣一點(diǎn),而上海不喜歡吃辣的,所以上海的

所有絕味的東西都不會(huì)做的像南昌的那樣辣,然而這點(diǎn)不同導(dǎo)致南昌絕味工廠和上海的絕味工廠生成所有絕味的

產(chǎn)品都不同,也就是某個(gè)具體工廠需要負(fù)責(zé)一系列產(chǎn)品(指的是絕味所有食物)的創(chuàng)建工作,下面就具體看看如何

使用抽象工廠模式來(lái)實(shí)現(xiàn)這種情況。

///下面以絕味鴨脖連鎖店為例子演示下抽象工廠模式

///因?yàn)槊總€(gè)地方的喜歡的口味不一樣,有些地方喜歡辣點(diǎn)的,有些地方喜歡吃不辣點(diǎn)

///客戶(hù)端調(diào)用

6classClient

7{

8staticvoidMain(string[]args)

9(

10//南昌工廠制作南昌的鴨脖和鴨架

11AbstractFactorynanChangFactory=newNanChangFactory();

12YaBonanChangYabo=nanChangFactory.CreateYaBoO;

13nanChangYabo.Print();

14YajiananChangYajia=nanChangFactory.CreateYaJia();

15nanChangYajia.Print();

17//上海工廠制作上海的鴨脖和鴨架

18AbstractFactoryshangHaiFactory=newShangHaiFactory();

19shangHaiFactory.CreateYaBo().Print();

20shangHaiFactory.CreateYaJia().Print();

22Console.Read();

23)

24)

27///抽象工廠類(lèi),提供創(chuàng)建兩個(gè)不同地方的鴨架和鴨脖的接口

29publicabstractclassAbstractFactory

30(

31//抽象工廠提供創(chuàng)建一系列產(chǎn)品的接口,這里作為例子,只給出了絕味中鴨脖和鴨

架的創(chuàng)建接口

32publieabstractYaBoCreateYaBoO;

33publicabstractYajiaCreateYaJia();

34)

37〃/南昌絕味工廠負(fù)責(zé)制作南昌的鴨脖和鴨架

39publieclassNanChangFactory:AbstractFactory

40(

41//制作南昌鴨脖

42publicoverrideYaBoCreateYaBo()

43{

44returnnewNanChangYaBo();

45)

46//制作南昌鴨架

47publicoverrideYajiaCreateYaJia()

48(

49returnnewNanChangYaJia();

50)

51

54///上海絕味工廠負(fù)責(zé)制作上海的鴨脖和鴨架

56publicclassShangHaiFactory:AbstractFactory

57(

58//制作上海鴨脖

59publicoverrideYaBoCreateYaBo()

60{

61returnnewShangHaiYaBo();

62)

63//制作上海鴨架

64publicoverrideYajiaCreateYaJia()

65{

66returnnewShangHaiYaJia();

67)

68)

71///鴨脖抽象類(lèi),供每個(gè)地方的鴨脖類(lèi)繼承

73publicabstractclassYaBo

74(

76///打印方法,用于輸出信息

78publicabstractvoidPrint();

79)

82///鴨架抽象類(lèi),供每個(gè)地方的鴨架類(lèi)繼承

84publicabstractclassYajia

85(

87///打印方法,用于輸出信息

89publicabstractvoidPrint();

90)

93///南昌的鴨脖類(lèi),因?yàn)榻魅讼矚g吃辣的,所以南昌的鴨脖稍微會(huì)比上海做的辣

95publicclassNanChangYaBo:YaBo

96(

97publicoverridevoidPrint()

98(

99Console.WriteLine("南昌的鴨脖”);

100)

101)

104///上海的鴨脖沒(méi)有南昌的鴨脖做的辣

106publicclassShangHaiYaBo:YaBo

107(

108publicoverridevoidPrint()

109(

110Console.WriteLine("上海的鴨脖”);

111)

112)

115///南昌的鴨架

117publicclassNanChangYaJia:Yajia

118(

119publicoverridevoidPrint()

120

121Console.WriteLine(“南昌的鴨架子”);

122)

123)

126///上海的鴨架

128publicclassShangHaiYaJia:Yajia

129(

130publicoverridevoidPrint()

131(

132Console.WriteLine(“上海的鴨架子”);

133)

134)

上面代碼中都有詳細(xì)的注釋?zhuān)@里就不再解釋上面的代碼了,下面就具體看看抽象工廠模式的定義吧(理解定義

可以參考上面的實(shí)現(xiàn)來(lái)加深理解):

抽象工廠模式;提供一個(gè)創(chuàng)建產(chǎn)品的接口來(lái)負(fù)責(zé)創(chuàng)建相關(guān)或依賴(lài)的對(duì)象,而不具體明確指定具體類(lèi)

抽象工廠允許客戶(hù)使用抽象的接口來(lái)創(chuàng)建一組相關(guān)產(chǎn)品,而不需要知道或關(guān)心實(shí)際生產(chǎn)出的具體產(chǎn)品是什么。這

樣客戶(hù)就可以從具體產(chǎn)品中被解耦。下面通過(guò)抽象工模式的類(lèi)圖來(lái)了解各個(gè)類(lèi)中之間的關(guān)系:

2.3抽象工廠應(yīng)對(duì)需求變更

看完上面抽象工廠的實(shí)現(xiàn)之后,如果“絕味”公司又想在湖南開(kāi)一家分店怎么辦呢?因?yàn)楹先讼矚g吃麻辣

的,下面就具體看看應(yīng)用了抽象工廠模式的系統(tǒng)是如何應(yīng)對(duì)這種需求的。

///如果絕味又想開(kāi)一家湖南的分店時(shí),因?yàn)楹舷矚g吃麻的

///所以這是有需要有一家湖南的工廠專(zhuān)門(mén)制作

publicclassHuNanFactory:AbstractFactory

(

//制作湖南鴨脖

publicoverrideYaBoCreateYaBo()

(

returnnewHuNanYaBo();

)

//制作湖南鴨架

publicoverrideYajiaCreateYaJia()

(

returnnewHuNanYajia();

}

}

///湖南的鴨脖

publicclassHuNanYaBo:YaBo

(

publicoverridevoidPrint()

(

Console.WriteLine(“湖南的鴨脖”);

}

///湖南的鴨架

publicclassHuNanYajia:Yajia

(

publicoverridevoidPrint()

(

Console.WriteLine("湖南的鴨架子”);

)

)

此時(shí),只需要添加三個(gè)類(lèi):一個(gè)是湖南具體工廠類(lèi),負(fù)責(zé)創(chuàng)建湖南口味的鴨脖和鴨架,另外兩個(gè)類(lèi)是具有湖南口

味的鴨脖類(lèi)和鴨架類(lèi)。從上面代碼看出,抽象工廠對(duì)于系列產(chǎn)品的變化支持“開(kāi)放——封閉”原則(指的是要求

系統(tǒng)對(duì)擴(kuò)展開(kāi)放,對(duì)修改封閉),擴(kuò)展起來(lái)非常簡(jiǎn)便,但是,抽象工廠對(duì)于添加新產(chǎn)品這種情況就不支持“開(kāi)放

——封閉“原則,這也是抽象工廠的缺點(diǎn)所在,這點(diǎn)會(huì)在第四部分詳細(xì)介紹。

抽象工廠的分析

抽象工廠模式將具體產(chǎn)品的創(chuàng)建延遲到具體工廠的子類(lèi)中,這樣將對(duì)象的創(chuàng)建封裝起來(lái),可以減少客戶(hù)端與

具體產(chǎn)品類(lèi)之間的依賴(lài),從而使系統(tǒng)耦合度低,這樣更有利于后期的維護(hù)和擴(kuò)展,這真是抽象工廠模式的優(yōu)點(diǎn)所

在,然后抽象模式同時(shí)也存在不足的地方。下面就具體看下抽象工廠的缺點(diǎn)(缺點(diǎn)其實(shí)在前面的介紹中以已經(jīng)涉

及了):

抽象工廠模式很難支持新種類(lèi)產(chǎn)品的變化。這是因?yàn)槌橄蠊S接口中已經(jīng)確定了可以被創(chuàng)建的產(chǎn)品集合,如果

需要添加新產(chǎn)品,此時(shí)就必須去修改抽象工廠的接口,這樣就涉及到抽象工廠類(lèi)的以及所有子類(lèi)的改變,這樣

也就違背了“開(kāi)發(fā)——封閉”原則。

知道了抽象工廠的優(yōu)缺點(diǎn)之后,也就能很好地把握什么情況下考慮使用抽象工廠模式了,下面就具體看看使

用抽象工廠模式的系統(tǒng)應(yīng)該符合那幾個(gè)前提:

一個(gè)系統(tǒng)不要求依賴(lài)產(chǎn)品類(lèi)實(shí)例如何被創(chuàng)建、組合和表達(dá)的表達(dá),這點(diǎn)也是所有工廠模式應(yīng)用的前提。

這個(gè)系統(tǒng)有多個(gè)系列產(chǎn)品,而系統(tǒng)中只消費(fèi)其中某一系列產(chǎn)品

?系統(tǒng)要求提供一個(gè)產(chǎn)品類(lèi)的庫(kù),所有產(chǎn)品以同樣的接口出現(xiàn),客戶(hù)端不需要依賴(lài)具體實(shí)現(xiàn)。

(5)建造者模式(BUILDER)

在軟件系統(tǒng)中,有時(shí)需要?jiǎng)?chuàng)建一個(gè)復(fù)雜對(duì)象,并且這個(gè)復(fù)雜對(duì)象由其各部分子對(duì)象通過(guò)一定的步驟組合而成。例如一個(gè)采購(gòu)系統(tǒng)中,

如果需要采購(gòu)員去采購(gòu)一批電腦時(shí),在這個(gè)實(shí)際需求中,電腦就是一個(gè)復(fù)雜的對(duì)象,它是由CPU、主板、硬盤(pán)、顯卡、機(jī)箱等組

裝而成的,如果此時(shí)讓采購(gòu)員一臺(tái)一臺(tái)電腦去組裝的話(huà)真是要累死采購(gòu)員了,這里就可以采用建造者模式來(lái)解決這個(gè)問(wèn)題,我們可

以把電腦的各個(gè)組件的組裝過(guò)程封裝到一個(gè)建造者類(lèi)對(duì)象里,建造者只要負(fù)責(zé)返還給客戶(hù)端全部組件都建造完畢的產(chǎn)品對(duì)象就可以

了。然而現(xiàn)實(shí)生活中也是如此的,如果公司要采購(gòu)一批電腦,此時(shí)采購(gòu)員不可能自己去買(mǎi)各個(gè)組件并把它們組織起來(lái),此時(shí)采購(gòu)員

只需要像電腦城的老板說(shuō)自己要采購(gòu)什么樣的電腦就可以了,電腦城老板自然會(huì)把組裝好的電腦送到公司。下面就以這個(gè)例子來(lái)展

開(kāi)建造者模式的介紹。

二、建造者模式的詳細(xì)介紹

在這個(gè)例子中,電腦城的老板是直接與客戶(hù)(也就是指采購(gòu)員)聯(lián)系的,然而電腦的組裝是由老板指揮裝機(jī)

人員去把電腦的各個(gè)部件組裝起來(lái),真真負(fù)責(zé)創(chuàng)建產(chǎn)品(這里產(chǎn)品指的就是電腦)的人就是電腦城的裝機(jī)人員。

理清了這個(gè)邏輯過(guò)程之后,下面就具體看下如何用代碼來(lái)表示這種現(xiàn)實(shí)生活中的邏輯過(guò)程:

1usingSystem;

2usingSystem.Collections.Generic;

3usingSystem.Linq;

4usingSystem.Text;

8///以組裝電腦為例子

9///每臺(tái)電腦的組成過(guò)程都是一致的,但是使用同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示(即可以

組裝成不一樣的電腦,配置不一樣)

10///組裝電腦的這個(gè)場(chǎng)景就可以應(yīng)用建造者模式來(lái)設(shè)計(jì)

12namespace設(shè)計(jì)模式之建造者模式

13(

15///客戶(hù)類(lèi)

17classCustomer

18{

19staticvoidMain(string[]args)

20{

21//客戶(hù)找到電腦城老板說(shuō)要買(mǎi)電腦,這里要裝兩臺(tái)電腦

22//創(chuàng)建指揮者和構(gòu)造者

23Directordirector=newDirector();

24Builderbl=newConcreteBuilderl();

25Builderb2=newConcreteBuilder2();

27//老板叫員工去組裝第一臺(tái)電腦

28director.Construct(bl);

30//組裝完,組裝人員搬來(lái)組裝好的電腦

31Computercomputeri=bl.GetComputer();

32computeri.Show();

33

34//老板叫員工去組裝第二臺(tái)電腦

35director.Construct(b2);

36Computercomputer2=b2.GetComputer();

37computer2.Show();

39Console.Read();

40)

41)

42

44///小王和小李難道會(huì)自愿地去組裝嘛,誰(shuí)不想休息的,這必須有一個(gè)人叫他們?nèi)ソM裝才

會(huì)去的

45///這個(gè)人當(dāng)然就是老板了,也就是建造者模式中的指揮者

46///指揮創(chuàng)建過(guò)程類(lèi)

48publieclassDirector

49(

50//組裝電腦

51publicvoidConstruct(Builderbuilder)

52(

53builder.BuildPartCPU();

54builder.BuildPartMainBoard();

55)

56)

59///電腦類(lèi)

61publieclassComputer

62(

63//電腦組件集合

64privateIList<string>parts=newList<string>();

65

66//把單個(gè)組件添加到電腦組件集合中

67publicvoidAdd(stringpart)

68(

69parts.Add(part);

70)

72publievoidShow()

73(

74Console.WriteLine("電腦開(kāi)始在組裝......”);

75foreach(stringpartinparts)

76{

77Console.WriteLine('組件"+part+"已裝好”);

78)

79

80Console.WriteLine("電腦組裝好了“);

81)

82)

85///抽象建造者,這個(gè)場(chǎng)景下為〃組裝人〃,這里也可以定義為接口

87publieabstractclassBuilder

88(

89//裝CPU

90publicabstractvoidBuildPartCPU();

91//裝主板

92publicabstractvoidBuildPartMainBoard();

94//當(dāng)然還有裝硬盤(pán),電源等組件,這里省略

96//獲得組裝好的電腦

97publicabstractComputerGetComputer();

98)

101///具體創(chuàng)建者,具體的某個(gè)人為具體創(chuàng)建者,例如:裝機(jī)小王啊

103publicclassConcreteBuilderl:Builder

104(

105Computercomputer=newComputer();

106publicoverridevoidBuildPartCPU()

107(

108computer.Add("CPUl");

109)

111publicoverridevoidBuildPartMainBoardO

112(

113computer.Add(/zMainboardl");

114)

116publicoverrideComputerGetComputer()

117(

118returncomputer;

119)

120)

123///具體創(chuàng)建者,具體的某個(gè)人為具體創(chuàng)建者,例如:裝機(jī)小李啊

124///又裝另一臺(tái)電腦了

126publicclassConcreteBuilder2:Builder

127(

128Computercomputer=newComputer();

129publicoverridevoidBuildPartCPU()

130(

131computer.Add(“CPU2");

132)

134publicoverridevoidBuildPartMainBoard()

135{

136computer.Add(/zMainboard2");

137)

139publicoverrideComputerGetComputer()

140(

141returncomputer;

142)

143}

144

介紹完了建造者模式的具體實(shí)現(xiàn)之后,下面具體看下建造者模式的具體定義是怎樣的。

建造者模式(BuilderPattern):將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的

表示。

建造者模式使得建造代碼與表示代碼的分離,可以使客戶(hù)端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié),從而降低了客戶(hù)端與

具體產(chǎn)品之間的耦合度,下面通過(guò)類(lèi)圖來(lái)幫助大家更好地理清建造者模式中類(lèi)之間的關(guān)系。

建造者模式的分析

介紹完了建造者模式的具體實(shí)現(xiàn)之后,讓我們總結(jié)下建造模式的實(shí)現(xiàn)要點(diǎn):

1.在建造者模式中,指揮者是直接與客戶(hù)端打交道的,指揮者將客戶(hù)端創(chuàng)建產(chǎn)品的請(qǐng)求劃分為對(duì)各個(gè)部件的建造請(qǐng)

求,再將這些請(qǐng)求委派到具體建造者角色,具體建造者角色是完成具體產(chǎn)品的構(gòu)建工作的,卻不為客戶(hù)所知道。

2.建造者模式主要用于“分步驟來(lái)構(gòu)建一個(gè)復(fù)雜的對(duì)象”,其中“分步驟”是一個(gè)固定的組合過(guò)程,而復(fù)雜對(duì)象的各個(gè)

部分是經(jīng)常變化的(也就是說(shuō)電腦的內(nèi)部組件是經(jīng)常變化的,這里指的的變化如硬盤(pán)的大小變了,CPU由單核

變雙核等)。

3.產(chǎn)品不需要抽象類(lèi),由于建造模式的創(chuàng)建出來(lái)的最終產(chǎn)品可能差異很大,所以不大可能提煉出一個(gè)抽象產(chǎn)品類(lèi)。

4.在前面文章中介紹的抽象工廠模式解決了“系列產(chǎn)品”的需求變化,而建造者模式解決的是“產(chǎn)品部分”的需要變

化。

5.由于建造者隱藏了具體產(chǎn)品的組裝過(guò)程,所以要改變一個(gè)產(chǎn)品的內(nèi)部表示,只需要再實(shí)現(xiàn)一個(gè)具體的建造者就可

以了,從而能很好地應(yīng)對(duì)產(chǎn)品組成組件的需求變化。

(6)原型模式(PROTOTYPE)

在軟件系統(tǒng)中,當(dāng)創(chuàng)建一個(gè)類(lèi)的實(shí)例的過(guò)程很昂貴或很復(fù)雜,并且我們需要?jiǎng)?chuàng)建多個(gè)這樣類(lèi)的實(shí)例時(shí),如果

我們用new操作符去創(chuàng)建這樣的類(lèi)實(shí)例,這未免會(huì)增加創(chuàng)建類(lèi)的復(fù)雜度和耗費(fèi)更多的內(nèi)存空間,因?yàn)檫@樣在內(nèi)

存中分配了多個(gè)一樣的類(lèi)實(shí)例對(duì)象,然后如果采用工廠模式來(lái)創(chuàng)建這樣的系統(tǒng)的話(huà),隨著產(chǎn)品類(lèi)的不斷增加,導(dǎo)

致子類(lèi)的數(shù)量不斷增多,反而增加了系統(tǒng)復(fù)雜程度,所以在這里使用工廠模式來(lái)封裝類(lèi)創(chuàng)建過(guò)程并不合適,然而

原型模式可以很好地解決這個(gè)問(wèn)題,因?yàn)槊總€(gè)類(lèi)實(shí)例都是相同的,當(dāng)我們需要多個(gè)相同的類(lèi)實(shí)例時(shí),沒(méi)必要每次

都使用new運(yùn)算符去創(chuàng)建相同的類(lèi)實(shí)例對(duì)象,此時(shí)我們一般思路就是想——只創(chuàng)建一個(gè)類(lèi)實(shí)例對(duì)象,如果后面

需要更多這樣的實(shí)例,可以通過(guò)對(duì)原來(lái)對(duì)象拷貝一份來(lái)完成創(chuàng)建,這樣在內(nèi)存中不需要?jiǎng)?chuàng)建多個(gè)相同的類(lèi)實(shí)例,

從而減少內(nèi)存的消耗和達(dá)到類(lèi)實(shí)例的復(fù)用。然而這個(gè)思路正是原型模式的實(shí)現(xiàn)方式。下面就具體介紹下設(shè)計(jì)模

式中的原型設(shè)計(jì)模式。

二、原型模式的詳細(xì)介紹

在現(xiàn)實(shí)生活中,也有很多原型設(shè)計(jì)模式的例子,例如,細(xì)胞分裂的過(guò)程,一個(gè)細(xì)胞的有絲分裂產(chǎn)生兩個(gè)相同的細(xì)

胞;還有西游記中孫悟空變出后孫的本領(lǐng)和火影忍者中鳴人的隱分身忍術(shù)等。下面就以孫悟空為例子來(lái)演示下原

型模式的實(shí)現(xiàn)。具體的實(shí)現(xiàn)代碼如下:

〃/火影忍者中鳴人的影分身和孫悟空的的變都是原型模式

classClient

(

staticvoidMain(string[]args)

{

//孫悟空原型

MonkeyKingPrototypeprototypeMonkeyKing=new

ConcretePrototype(〃MonkeyKing〃);

//變一個(gè)

MonkeyKingPrototypecloneMonkeyKing=prototypeMonkeyKing.Clone()as

ConcretePrototype;

Console.WriteLine(/zClonedl:\t/z+cloneMonkeyKing.Id);

//變兩個(gè)

MonkeyKingPrototypecloneMonkeyKing2=prototypeMonkeyKing.Clone()as

ConcretePrototype;

Console.WriteLine(/zCloned2:\t/z+cloneMonkeyKing2.Id);

Console.ReadLine();

)

)

///孫悟空原型

publicabstractclassMonkeyKingPrototype

{

publicstringId{get;set;}

publicMonkeyKingPrototype(stringid)

{

this.Id=id;

)

//克隆方法,即孫大圣說(shuō)“變”

publicabstractMonkeyKingPrototypeClone();

}

///創(chuàng)建具體原型

publicclassConcretePrototype:MonkeyKingPrototype

{

publicConcretePrototype(stringid)

:base(id)

{}

///淺拷貝

publicoverrideMonkeyKingPrototypeClone()

//調(diào)用MemberwiseClone方法實(shí)現(xiàn)的是淺拷貝,另外還有深拷貝

return(MonkeyKingPrototype)this.MemberwiseClone();

)

)

上面原型模式的運(yùn)行結(jié)果為(從運(yùn)行結(jié)果可以看出,創(chuàng)建的兩個(gè)拷貝對(duì)象的ID屬性都是與原型對(duì)象ID屬性一

樣的):

上面代碼實(shí)現(xiàn)的淺拷貝的方式,淺拷貝是指當(dāng)對(duì)象的字段值被拷貝時(shí),字段引用的對(duì)象不會(huì)被拷貝。例如,如果

一個(gè)對(duì)象有一個(gè)指向字符串的字段,并且我們對(duì)該對(duì)象做了一個(gè)淺拷貝,那么這兩個(gè)對(duì)象將引用同一個(gè)字符串,

而深拷貝是對(duì)對(duì)象實(shí)例中字段引用的對(duì)象也進(jìn)行拷貝,如果一個(gè)對(duì)象有一個(gè)指向字符串的字段,并且我們對(duì)該對(duì)

象進(jìn)行了深拷貝的話(huà),那么我們將創(chuàng)建一個(gè)對(duì)象和一個(gè)新的字符串,新的對(duì)象將引用新的字符串。也就是說(shuō),執(zhí)

行深拷貝創(chuàng)建的新對(duì)象和原來(lái)對(duì)象不會(huì)共享任何東西,改變一個(gè)對(duì)象對(duì)另外一個(gè)對(duì)象沒(méi)有任何影響,而執(zhí)行淺拷

貝創(chuàng)建的新對(duì)象與原來(lái)對(duì)象共享成員,改變一個(gè)對(duì)象,另外一個(gè)對(duì)象的成員也會(huì)改變。

介紹完原型模式的實(shí)現(xiàn)代碼之后,下面看下原型模式的類(lèi)圖,通過(guò)類(lèi)圖來(lái)理清原型模式實(shí)現(xiàn)中類(lèi)之間的關(guān)系。具

體類(lèi)圖如下:

Name:原空模式

AuttxxiLearnmgHard

三、原型模式的優(yōu)缺點(diǎn)

原型模式的優(yōu)點(diǎn)有:

1,原型模式向客戶(hù)隱藏了創(chuàng)建新實(shí)例的復(fù)雜性

2.原型模式允許動(dòng)態(tài)增加或較少產(chǎn)品類(lèi)。

3.原型模式簡(jiǎn)化了實(shí)例的創(chuàng)建結(jié)構(gòu),工廠方法模式需要有一個(gè)與產(chǎn)品類(lèi)等級(jí)結(jié)構(gòu)相同的等級(jí)結(jié)構(gòu),而原型模式不需

要這樣。

4.產(chǎn)品類(lèi)不需要事先確定產(chǎn)品的等級(jí)結(jié)構(gòu),因?yàn)樵湍J竭m用于任何的等級(jí)結(jié)構(gòu)

原型模式的缺點(diǎn)有:

1-每個(gè)類(lèi)必須配備一個(gè)克隆方法

2.配備克隆方法需要對(duì)類(lèi)的功能進(jìn)行通盤(pán)考慮,這對(duì)于全新的類(lèi)不是很難,但對(duì)于已有的類(lèi)不一定很容易,特別

當(dāng)一個(gè)類(lèi)引用不支持串行化的間接對(duì)象,或者引用含有循環(huán)結(jié)構(gòu)的時(shí)候。

(7)適配器模式(ADAPTER)

下面讓我們看看適配器的定義,適配器模式——把一個(gè)類(lèi)的接口變換成客戶(hù)端所期待的另一種接口,從而使

原本接口不匹配而無(wú)法一起工作的兩個(gè)類(lèi)能夠在一起工作。適配器模式有類(lèi)的適配器模式和對(duì)象的適配器模式兩

種形式,下面我們分別討論這兩種形式的實(shí)現(xiàn)和給出對(duì)應(yīng)的類(lèi)圖來(lái)幫助大家理清類(lèi)之間的關(guān)系。

類(lèi)的適配器模式實(shí)現(xiàn)

在這里以生活中的一個(gè)例子來(lái)進(jìn)行演示適配器模式的實(shí)現(xiàn),具體場(chǎng)景是:在生活中,我們買(mǎi)的電器插頭是2

個(gè)孔的,但是我們買(mǎi)的插座只有三個(gè)孔的,此時(shí)我們就希望電器的插頭可以轉(zhuǎn)換為三個(gè)孔的就好,這樣我們就可

以直接把它插在插座上,此時(shí)三個(gè)孔插頭就是客戶(hù)端期待的另一種接口,自然兩個(gè)孔的插頭就是現(xiàn)有的接口,適

配器模式就是用來(lái)完成這種轉(zhuǎn)換的,具體實(shí)現(xiàn)代碼如下:

usingSystem;

///這里以插座和插頭的例子來(lái)詮釋適配器模式

///現(xiàn)在我們買(mǎi)的電器插頭是2個(gè)孔,但是我們買(mǎi)的插座只有3個(gè)孔的

///這是我們想把電器插在插座上的話(huà)就需要一個(gè)電適配器

namespace設(shè)計(jì)模式之適配器模式

(

///客戶(hù)端,客戶(hù)想要把2個(gè)孔的插頭轉(zhuǎn)變成三個(gè)孔的插頭,這個(gè)轉(zhuǎn)變交給適配器就好

///既然適配器需要完成這個(gè)功能,所以它必須同時(shí)具體2個(gè)孔插頭和三個(gè)孔插頭的特征

classClient

{

staticvoidMain(string[]args)

(

//現(xiàn)在客戶(hù)端可以通過(guò)電適配要使用2個(gè)孔的插頭了

IThreeHolethreehole=newPowerAdapter();

threehole.Request();

Console.ReadLine();

)

)

///三個(gè)孔的插頭,也就是適配器模式中的目標(biāo)角色

publicinterfaceIThreeHole

{

voidRequest();

)

///兩個(gè)孔的插頭,源角色一一需要適配的類(lèi)

publicabstractclassTwoHole

{

publicvoidSpecificRequest()

Console.WriteLine(“我是兩個(gè)孔的插頭“);

///適配器類(lèi),接口要放在類(lèi)的后面

///適配器類(lèi)提供了三個(gè)孔插頭的行為,但其本質(zhì)是調(diào)用兩個(gè)孔插頭的方法

publicclassPowerAdapter:TwoHole,IThreeHole

///實(shí)現(xiàn)三個(gè)孔插頭接口方法

publicvoidRequest()

//調(diào)用兩個(gè)孔插頭方法

this.SpecificRequest();

從上面代碼中可以看出,客戶(hù)端希望調(diào)用Request方法(即三個(gè)孔插頭),但是我們現(xiàn)有的類(lèi)(即2個(gè)孔

的插頭)并沒(méi)有Request方法,它只有SpecificRequest方法(即兩個(gè)孔插頭本身的方法),然而適配器類(lèi)(適

配器必須實(shí)現(xiàn)三個(gè)孔插頭接口和繼承兩個(gè)孔插頭類(lèi))可以提供這種轉(zhuǎn)換,它提供了Request方法的實(shí)現(xiàn)(其內(nèi)

部調(diào)用的是兩個(gè)孔插頭,因?yàn)檫m配器只是一個(gè)外殼罷了,包裝著兩個(gè)孔插頭(因?yàn)橹挥羞@樣,電器才能使用),

并向外界提供三個(gè)孔插頭的外觀,)以供客戶(hù)端使用。

類(lèi)圖

上面實(shí)現(xiàn)中,因?yàn)檫m配器(PowerAdapter類(lèi))與源角色(TwoHole類(lèi))是繼承關(guān)系,所以該適配器模式是類(lèi)

的適配器模式,具體對(duì)應(yīng)的類(lèi)圖為:

<〈Interface>>

ClientTarget?源角色:被適配器適配的類(lèi)^1

+Reque<;tO

△△

目標(biāo)角色:客戶(hù)湍期望的接口,

由于C:不支持多維承,

所以IBTarge虎義為接口

對(duì)象的適配器模式

上面都是類(lèi)的適配器模式的介紹,然而適配器模式還有另外一種形式——

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論