




版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 7 開(kāi)國(guó)大典 教學(xué)設(shè)計(jì)-2024-2025學(xué)年統(tǒng)編版語(yǔ)文六年級(jí)上冊(cè)
- 2023八年級(jí)數(shù)學(xué)下冊(cè) 第十六章 二次根式本章專(zhuān)題整合訓(xùn)練教學(xué)設(shè)計(jì) (新版)新人教版
- 10自然世界與人工世界 ( 教學(xué)設(shè)計(jì))一年級(jí)上冊(cè)科學(xué)蘇教版
- 2023八年級(jí)英語(yǔ)下冊(cè) Unit 9 Have you ever been to a museum Section A 第2課時(shí) (3a-4c)教學(xué)設(shè)計(jì) (新版)人教新目標(biāo)版
- 2023一年級(jí)數(shù)學(xué)上冊(cè) 二 10以?xún)?nèi)數(shù)的認(rèn)識(shí)和加減法(二)加減混合運(yùn)算教學(xué)設(shè)計(jì) 西師大版
- 輪椅的選擇和使用安全
- 2024-2025學(xué)年高中物理 第一章 分子動(dòng)理論 第4節(jié) 分子間的相互作用力教學(xué)設(shè)計(jì) 粵教版選修3-3
- 《設(shè)計(jì)食譜》(教案)-2024-2025學(xué)年五年級(jí)上冊(cè)勞動(dòng)人教版
- 9《黃山奇石》教學(xué)設(shè)計(jì)-2024-2025學(xué)年統(tǒng)編版(五四制)語(yǔ)文二年級(jí)上冊(cè)
- 綠色清新個(gè)人工作總結(jié)
- 《中國(guó)老年糖尿病診療指南(2024版)》解讀課件
- 2025年高考政治一輪復(fù)習(xí)知識(shí)清單選擇性必修三 《邏輯與思維》知識(shí)點(diǎn)復(fù)習(xí)
- 初三班級(jí)學(xué)生中考加油家長(zhǎng)會(huì)課件
- 廣東省2024年修訂醫(yī)療服務(wù)價(jià)格項(xiàng)目表
- 基于物聯(lián)網(wǎng)的農(nóng)產(chǎn)品質(zhì)量安全監(jiān)測(cè)平臺(tái)建設(shè)方案
- 臨床腸氣囊腫病影像診斷與鑒別
- 產(chǎn)學(xué)合作協(xié)同育人項(xiàng)目教學(xué)內(nèi)容和課程體系改革項(xiàng)目申報(bào)書(shū)模板-基于產(chǎn)業(yè)學(xué)院的實(shí)踐應(yīng)用型人才培養(yǎng)
- 2023年上海市普通高中學(xué)業(yè)水平合格性考試地理試題及答案
- 楊必勝-無(wú)人系統(tǒng)自主協(xié)同三維信息獲取
- 2024年煙葉制絲操作工(二級(jí))理論考試題庫(kù)大全-上(單選題)
- T-CPQS C010-2024 鑒賞收藏用潮流玩偶及類(lèi)似用途產(chǎn)品
評(píng)論
0/150
提交評(píng)論