23種設(shè)計模式

創(chuàng)建型

  1. Factory Method(工廠方法)

  2. Abstract Factory(抽象工廠)

  3. Builder(建造者)

  4. Prototype(原型)

  5. Singleton(單例)

結(jié)構(gòu)型

  1. Adapter Class/Object(適配器)

  2. Bridge(橋接)

  3. Composite(組合)

  4. Decorator(裝飾)

  5. Facade(外觀)

  6. Flyweight(享元)

  7. Proxy(代理)

行為型

  1. Interpreter(解釋器)

  2. Template Method(模板方法)

  3. Chain of Responsibility(責(zé)任鏈)

  4. Command(命令)

  5. Iterator(迭代器)

  6. Mediator(中介者)

  7. Memento(備忘錄)

  8. Observer(觀察者)

  9. State(狀態(tài))

  10. Strategy(策略)

  11. Visitor(訪問者)

創(chuàng)建型

1. Factory Method(工廠方法)

clip_image001

意圖:

定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類。Factory Method使個類的實例化延遲到其子類。

適用性:

當(dāng)一個類不知道它所必須創(chuàng)建的對象的類的時候。

當(dāng)一個類希望由它的子類來指定它所創(chuàng)建的對象的時候。

當(dāng)類將創(chuàng)建對象的職責(zé)委托給多個幫助子類中的某一個,并且你希望將哪一個幫助子類是代理者這一信息局部化的時候。

2. Abstract Factory(抽象工廠)

clip_image002

意圖:

提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們具體的類。適用性:

一個系統(tǒng)要獨立于它的產(chǎn)品的創(chuàng)建、組合和表示時。

一個系統(tǒng)要由多個產(chǎn)品系列中的一個來配置時。

當(dāng)你要強調(diào)一系列相關(guān)的產(chǎn)品對象的設(shè)計以便進(jìn)行聯(lián)合使用時。

當(dāng)你提供一個產(chǎn)品類庫,而只想顯示它們的接口而不是實現(xiàn)時。

3. Builder(建造者)

clip_image003

意圖:

將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。

適用性:

當(dāng)創(chuàng)建復(fù)雜對象的算法應(yīng)該獨立于該對象的組成部分以及它們的裝配方式時。

當(dāng)構(gòu)造過程必須允許被構(gòu)造的對象有不同的表示時。

4. Prototype(原型)

clip_image004

意圖:

用原型實例指定創(chuàng)建對象的種類,并且通過拷貝這些原型創(chuàng)建新的對象。

適用性:

當(dāng)要實例化的類是在運行時刻指定時,例如,通過動態(tài)裝載;或者為了避免創(chuàng)建一個與產(chǎn)品類層次平行的工廠類層次時;或者當(dāng)一個類的實例只能有幾個不同狀態(tài)組合中的一種時。建立相應(yīng)數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實例化該類更方便一些。

5. Singleton(單例)

clip_image005

意圖:

保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

適用性:

當(dāng)類只能有一個實例而且客戶可以從一個眾所周知的訪問點訪問它時。

當(dāng)這個唯一實例應(yīng)該是通過子類化可擴(kuò)展的,并且客戶應(yīng)該無需更改代碼就能使用一個擴(kuò)展的實例時。

結(jié)構(gòu)型

6. Adapter Class/Object(適配器)

clip_image006
意圖:

將一個類的接口轉(zhuǎn)換成客戶希望的另外一個接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。

適用性:

你想使用一個已經(jīng)存在的類,而它的接口不符合你的需求。

你想創(chuàng)建一個可以復(fù)用的類,該類可以與其他不相關(guān)的類或不可預(yù)見的類(即那些接口可能不一定兼容的類)協(xié)同工作。

(僅適用于對象Adapter)你想使用一些已經(jīng)存在的子類,但是不可能對每一個都進(jìn)行子類化以匹配它們的接口。對象適配器可以適配它的父類接口。

7. Bridge(橋接)

clip_image007

意圖:

將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨立地變化。

適用性:

你不希望在抽象和它的實現(xiàn)部分之間有一個固定的綁定關(guān)系。例如這種情況可能是因為,在程序運行時刻實現(xiàn)部分應(yīng)可以被選擇或者切換。

類的抽象以及它的實現(xiàn)都應(yīng)該可以通過生成子類的方法加以擴(kuò)充。這時Bridge模式使你可以對不同的抽象接口和實現(xiàn)部分進(jìn)行組合,并分別對它們進(jìn)行擴(kuò)充。

對一個抽象的實現(xiàn)部分的修改應(yīng)對客戶不產(chǎn)生影響,即客戶的代碼不必重新編譯。

(C++)你想對客戶完全隱藏抽象的實現(xiàn)部分。在C++中,類的表示在類接口中是可見的。

有許多類要生成。這樣一種類層次結(jié)構(gòu)說明你必須將一個對象分解成兩個部分。Rumbaugh稱這種類層次結(jié)構(gòu)為“嵌套的普化”(nested generalizations )。

你想在多個對象間共享實現(xiàn)(可能使用引用計數(shù)),但同時要求客戶并不知道這一點。一個簡單的例子便是Coplien的String類[ Cop92 ],在這個類中多個對象可以共享同一個字符串表示(StringRep)。

8. Composite(組合)

clip_image008
意圖:

將對象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。C o m p o s i t e 使得用戶對單個對象和組合對象的使用具有一致性。適用性:

你想表示對象的部分-整體層次結(jié)構(gòu)。

你希望用戶忽略組合對象與單個對象的不同,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對象。

9. Decorator(裝飾)

clip_image009
意圖:動態(tài)地給一個對象添加一些額外的職責(zé)。就增加功能來說,Decorator模式相比生成子類更為靈活。適用性:

在不影響其他對象的情況下,以動態(tài)、透明的方式給單個對象添加職責(zé)。

處理那些可以撤消的職責(zé)。

當(dāng)不能采用生成子類的方法進(jìn)行擴(kuò)充時。一種情況是,可能有大量獨立的擴(kuò)展,為支持每一種組合將產(chǎn)生大量的子類,使得子類數(shù)目呈爆炸性增長。另一種情況可能是因為類定義被隱藏,或類定義不能用于生成子類。

10. Facade(外觀)

clip_image010

意圖:

為子系統(tǒng)中的一組接口提供一個一致的界面,F(xiàn)acade模式定義了一個高層接口,這個接口使得這一子系統(tǒng)更加容易使用。

適用性:

當(dāng)你要為一個復(fù)雜子系統(tǒng)提供一個簡單接口時。子系統(tǒng)往往因為不斷演化而變得越來越復(fù)雜。大多數(shù)模式使用時都會產(chǎn)生更多更小的類。這使得子系統(tǒng)更具可重用性,也更容易對子系統(tǒng)進(jìn)行定制,但這也給那些不需要定制子系統(tǒng)的用戶帶來一些使用上的困難。Facade可以提供一個簡單的缺省視圖,這一視圖對大多數(shù)用戶來說已經(jīng)足夠,而那些需要更多的可定制性的用戶可以越過facade層。

客戶程序與抽象類的實現(xiàn)部分之間存在著很大的依賴性。引入facade將這個子系統(tǒng)與客戶以及其他的子系統(tǒng)分離,可以提高子系統(tǒng)的獨立性和可移植性。

當(dāng)你需要構(gòu)建一個層次結(jié)構(gòu)的子系統(tǒng)時,使用facade模式定義子系統(tǒng)中每層的入口點。如果子系統(tǒng)之間是相互依賴的,你可以讓它們僅通過facade進(jìn)行通訊,從而簡化了它們之間的依賴關(guān)系。

11. Flyweight(享元)

clip_image011

意圖:

運用共享技術(shù)有效地支持大量細(xì)粒度的對象。

適用性:

一個應(yīng)用程序使用了大量的對象。

完全由于使用大量的對象,造成很大的存儲開銷。

對象的大多數(shù)狀態(tài)都可變?yōu)橥獠繝顟B(tài)。

如果刪除對象的外部狀態(tài),那么可以用相對較少的共享對象取代很多組對象。

應(yīng)用程序不依賴于對象標(biāo)識。由于Flyweight對象可以被共享,對于概念上明顯有別的對象,標(biāo)識測試將返回真值。

12. Proxy(代理)

clip_image012

意圖:

為其他對象提供一種代理以控制對這個對象的訪問。

適用性:

在需要用比較通用和復(fù)雜的對象指針代替簡單的指針的時候,使用Proxy模式。下面是一些可以使用Proxy模式常見情況:

  1. 遠(yuǎn)程代理(Remote Proxy)為一個對象在不同的地址空間提供局部代表。 NEXTSTEP[Add94]使用NXProxy類實現(xiàn)了這一目的。Coplien[Cop92]稱這種代理為“大使”(Ambassador)。
    2 )虛代理(Virtual Proxy)根據(jù)需要創(chuàng)建開銷很大的對象。在動機一節(jié)描述的ImageProxy就是這樣一種代理的例子。
  2. 保護(hù)代理(Protection Proxy)控制對原始對象的訪問。保護(hù)代理用于對象應(yīng)該有不同的訪問權(quán)限的時候。例如,在Choices操作系統(tǒng)[ CIRM93]中KemelProxies為操作系統(tǒng)對象提供了訪問保護(hù)。
    4 )智能指引(Smart Reference)取代了簡單的指針,它在訪問對象時執(zhí)行一些附加操作。它的典型用途包括:

對指向?qū)嶋H對象的引用計數(shù),這樣當(dāng)該對象沒有引用時,可以自動釋放它(也稱為SmartPointers[Ede92 ] )。

當(dāng)?shù)谝淮我靡粋€持久對象時,將它裝入內(nèi)存。

在訪問一個實際對象前,檢查是否已經(jīng)鎖定了它,以確保其他對象不能改變它。

行為型

13. Interpreter(解釋器)

clip_image013

意圖:

給定一個語言,定義它的文法的一種表示,并定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。

適用性:

當(dāng)有一個語言需要解釋執(zhí)行,并且你可將該語言中的句子表示為一個抽象語法樹時,可使用解釋器模式。而當(dāng)存在以下情況時該模式效果最好:

該文法簡單對于復(fù)雜的文法,文法的類層次變得龐大而無法管理。此時語法分析程序生成器這樣的工具是更好的選擇。它們無需構(gòu)建抽象語法樹即可解釋表達(dá)式,這樣可以節(jié)省空間而且還可能節(jié)省時間。

效率不是一個關(guān)鍵問題最高效的解釋器通常不是通過直接解釋語法分析樹實現(xiàn)的,而是首先將它們轉(zhuǎn)換成另一種形式。例如,正則表達(dá)式通常被轉(zhuǎn)換成狀態(tài)機。但即使在這種情況下,轉(zhuǎn)換器仍可用解釋器模式實現(xiàn),該模式仍是有用的。

14. Template Method(模板方法)

clip_image014

意圖:

定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。TemplateMethod使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。

適用性:

一次性實現(xiàn)一個算法的不變的部分,并將可變的行為留給子類來實現(xiàn)。

各子類中公共的行為應(yīng)被提取出來并集中到一個公共父類中以避免代碼重復(fù)。這是Opdyke和Johnson所描述過的“重分解以一般化”的一個很好的例子[ OJ93 ]。首先識別現(xiàn)有代碼中的不同之處,并且將不同之處分離為新的操作。最后,用一個調(diào)用這些新的操作的模板方法來替換這些不同的代碼。

控制子類擴(kuò)展。模板方法只在特定點調(diào)用“hook ”操作(參見效果一節(jié)),這樣就只允許在這些點進(jìn)行擴(kuò)展。

15. Chain of Responsibility(責(zé)任鏈)

clip_image015

意圖:

使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接收者之間的耦合關(guān)系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。

適用性:

有多個的對象可以處理一個請求,哪個對象處理該請求運行時刻自動確定。

你想在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。

可處理一個請求的對象集合應(yīng)被動態(tài)指定。

16. Command(命令)

clip_image016

意圖:

將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進(jìn)行參數(shù)化;對請求排隊或記錄請求日志,以及支持可撤消的操作。

適用性:

抽象出待執(zhí)行的動作以參數(shù)化某對象,你可用過程語言中的回調(diào)(call back)函數(shù)表達(dá)這種參數(shù)化機制。所謂回調(diào)函數(shù)是指函數(shù)先在某處注冊,而它將在稍后某個需要的時候被調(diào)用。Command模式是回調(diào)機制的一個面向?qū)ο蟮奶娲贰?/p>

在不同的時刻指定、排列和執(zhí)行請求。一個Command對象可以有一個與初始請求無關(guān)的生存期。如果一個請求的接收者可用一種與地址空間無關(guān)的方式表達(dá),那么就可將負(fù)責(zé)該請求的命令對象傳送給另一個不同的進(jìn)程并在那兒實現(xiàn)該請求。

支持取消操作。Command的Excute操作可在實施操作前將狀態(tài)存儲起來,在取消操作時這個狀態(tài)用來消除該操作的影響。Command接口必須添加一個Unexecute操作,該操作取消上一次Execute調(diào)用的效果。執(zhí)行的命令被存儲在一個歷史列表中??赏ㄟ^向后和向前遍歷這一列表并分別調(diào)用Unexecute和Execute來實現(xiàn)重數(shù)不限的“取消”和“重做”。

支持修改日志,這樣當(dāng)系統(tǒng)崩潰時,這些修改可以被重做一遍。在Command接口中添加裝載操作和存儲操作,可以用來保持變動的一個一致的修改日志。從崩潰中恢復(fù)的過程包括從磁盤中重新讀入記錄下來的命令并用Execute操作重新執(zhí)行它們。

用構(gòu)建在原語操作上的高層操作構(gòu)造一個系統(tǒng)。這樣一種結(jié)構(gòu)在支持事務(wù)( transaction)的信息系統(tǒng)中很常見。一個事務(wù)封裝了對數(shù)據(jù)的一組變動。Command模式提供了對事務(wù)進(jìn)行建模的方法。Command有一個公共的接口,使得你可以用同一種方式調(diào)用所有的事務(wù)。同時使用該模式也易于添加新事務(wù)以擴(kuò)展系統(tǒng)。

17. Iterator(迭代器)

clip_image017

意圖:

提供一種方法順序訪問一個聚合對象中各個元素,而又不需暴露該對象的內(nèi)部表示。

適用性:

訪問一個聚合對象的內(nèi)容而無需暴露它的內(nèi)部表示。

支持對聚合對象的多種遍歷。

為遍歷不同的聚合結(jié)構(gòu)提供一個統(tǒng)一的接口(即,支持多態(tài)迭代)。

18. Mediator(中介者)

clip_image018

意圖:

用一個中介對象來封裝一系列的對象交互。中介者使各對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。

適用性:

一組對象以定義良好但是復(fù)雜的方式進(jìn)行通信。產(chǎn)生的相互依賴關(guān)系結(jié)構(gòu)混亂且難以理解。

一個對象引用其他很多對象并且直接與這些對象通信,導(dǎo)致難以復(fù)用該對象。

想定制一個分布在多個類中的行為,而又不想生成太多的子類。

19. Memento(備忘錄)

clip_image019

意圖:

在不破壞封裝性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣以后就可將該對象恢復(fù)到原先保存的狀態(tài)。

適用性:

必須保存一個對象在某一個時刻的(部分)狀態(tài),這樣以后需要時它才能恢復(fù)到先前的狀態(tài)。

如果一個用接口來讓其它對象直接得到這些狀態(tài),將會暴露對象的實現(xiàn)細(xì)節(jié)并破壞對象的封裝性。

20. Observer(觀察者)

clip_image020

意圖:

定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新。

適用性:

當(dāng)一個抽象模型有兩個方面,其中一個方面依賴于另一方面。將這二者封裝在獨立的對象中以使它們可以各自獨立地改變和復(fù)用。

當(dāng)對一個對象的改變需要同時改變其它對象,而不知道具體有多少對象有待改變。

當(dāng)一個對象必須通知其它對象,而它又不能假定其它對象是誰。換言之,你不希望這些對象是緊密耦合的。

21. State(狀態(tài))

clip_image021

意圖:

允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為。對象看起來似乎修改了它的類。

適用性:

一個對象的行為取決于它的狀態(tài),并且它必須在運行時刻根據(jù)狀態(tài)改變它的行為。

一個操作中含有龐大的多分支的條件語句,且這些分支依賴于該對象的狀態(tài)。這個狀態(tài)通常用一個或多個枚舉常量表示。通常,有多個操作包含這一相同的條件結(jié)構(gòu)。State模式將每一個條件分支放入一個獨立的類中。這使得你可以根據(jù)對象自身的情況將對象的狀態(tài)作為一個對象,這一對象可以不依賴于其他對象而獨立變化。

22. Strategy(策略)

clip_image022

意圖:

定義一系列的算法,把它們一個個封裝起來,并且使它們可相互替換。本模式使得算法可獨立于使用它的客戶而變化。

適用性:

許多相關(guān)的類僅僅是行為有異?!安呗浴碧峁┝艘环N用多個行為中的一個行為來配置一個類的方法。

需要使用一個算法的不同變體。例如,你可能會定義一些反映不同的空間/時間權(quán)衡的算法。當(dāng)這些變體實現(xiàn)為一個算法的類層次時[H087] ,可以使用策略模式。

算法使用客戶不應(yīng)該知道的數(shù)據(jù)。可使用策略模式以避免暴露復(fù)雜的、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)

一個類定義了多種行為,并且這些行為在這個類的操作中以多個條件語句的形式出現(xiàn)。將相關(guān)的條件分支移入它們各自的Strategy類中以代替這些條件語句。

23. Visitor(訪問者)

clip_image023

意圖:

定義一個操作中的算法的骨架,而將一些步驟延遲到子類中。TemplateMethod使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。

適用性:

一次性實現(xiàn)一個算法的不變的部分,并將可變的行為留給子類來實現(xiàn)。

各子類中公共的行為應(yīng)被提取出來并集中到一個公共父類中以避免代碼重復(fù)。這是Opdyke和Johnson所描述過的“重分解以一般化”的一個很好的例子[OJ93]。首先識別現(xiàn)有代碼中的不同之處,并且將不同之處分離為新的操作。最后,用一個調(diào)用這些新的操作的模板方法來替換這些不同的代碼。

控制子類擴(kuò)展。模板方法只在特定點調(diào)用“hook ”操作(參見效果一節(jié)),這樣就只允許在這些點進(jìn)行擴(kuò)展。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容