設(shè)計(jì)模式 - 一種由經(jīng)驗(yàn)總結(jié)出的模式
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。 毫無疑問,設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的,設(shè)計(jì)模式使代碼編制真正工程化,設(shè)計(jì)模式是軟件工程的基石,如同大廈的一塊塊磚石一樣。項(xiàng)目中合理的運(yùn)用設(shè)計(jì)模式可以完美地解決很多問題,每種模式在現(xiàn)在中都有相應(yīng)的原理來與之對(duì)應(yīng),每一個(gè)模式描述了一個(gè)在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的核心解決方案,這也是它能被廣泛應(yīng)用的原因。

設(shè)計(jì)框架
可復(fù)用面向?qū)ο筌浖到y(tǒng)一般劃分為兩大類:應(yīng)用程序工具箱和框架 - Framework,我們平時(shí)開發(fā)的具體軟件都是應(yīng)用程序,java的API屬于工具箱;而框架是構(gòu)成一類特定軟件可復(fù)用設(shè)計(jì)的一組相互協(xié)作的類,EJB - EnterpriseJavaBeans是Java應(yīng)用于企業(yè)計(jì)算的框架。
框架通常定義了應(yīng)用體系的整體結(jié)構(gòu)類和對(duì)象的關(guān)系等等設(shè)計(jì)參數(shù),以便于具體應(yīng)用實(shí)現(xiàn)者能集中精力于應(yīng)用本身的特定細(xì)節(jié)??蚣苤饕涗涇浖?yīng)用中共同的設(shè)計(jì)決策,框架強(qiáng)調(diào)設(shè)計(jì)復(fù)用,因此框架設(shè)計(jì)中必然要使用設(shè)計(jì)模式。
另外,設(shè)計(jì)模式有助于對(duì)框架結(jié)構(gòu)的理解,成熟的框架通常使用了多種設(shè)計(jì)模式,如果你熟悉這些設(shè)計(jì)模式,毫無疑問,你將迅速掌握框架的結(jié)構(gòu),我們一般開發(fā)者如果突然接觸EJBJ2EE等框架,會(huì)覺得特別難學(xué),難掌握,那么轉(zhuǎn)而先掌握設(shè)計(jì)模式,無疑是給了你剖析EJB或J2EE系統(tǒng)的一把利器。
設(shè)計(jì)原則
為什么要提倡"Design Pattern"呢?根本原因是為了代碼復(fù)用,增加可維護(hù)性。那么怎么才能實(shí)現(xiàn)代碼復(fù)用呢?面向?qū)ο笥袔讉€(gè)原則:開閉原則 - Open Closed Principle,OCP、里氏代換原則(Liskov Substitution Principle,LSP)、依賴倒轉(zhuǎn)原則(Dependency Inversion Principle,DIP)、接口隔離原則(Interfce Segregation Principle,ISP)、合成/聚合復(fù)用原則(Composite/Aggregate Reuse Principle,CARP)、最小知識(shí)原則(Principle of Least Knowledge,PLK,也叫迪米特法則)。開閉原則具有理想主義的色彩,它是面向?qū)ο笤O(shè)計(jì)的終極目標(biāo)。其他幾條,則可以看做是開閉原則的實(shí)現(xiàn)方法。
設(shè)計(jì)模式就是實(shí)現(xiàn)了這些原則,從而達(dá)到了代碼復(fù)用、增加可維護(hù)性的目的。
依賴倒轉(zhuǎn)原則
抽象不應(yīng)該依賴于細(xì)節(jié),細(xì)節(jié)應(yīng)當(dāng)依賴于抽象。
要針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程。
傳遞參數(shù),或者在組合聚合關(guān)系中,盡量引用層次高的類。
主要是在構(gòu)造對(duì)象時(shí)可以動(dòng)態(tài)的創(chuàng)建各種具體對(duì)象,當(dāng)然如果一些具體類比較穩(wěn)定,就不必在弄一個(gè)抽象類做它的父類,這樣有畫蛇添足的感覺
接口隔離原則
定制服務(wù)的例子,每一個(gè)接口應(yīng)該是一種角色,不多不少,不干不該干的事,該干的事都要干。
合成/聚合復(fù)用原則
合成/聚合復(fù)用原則 - Composite/Aggregate Reuse Principle ,CARP經(jīng)常又叫做合成復(fù)用原則。合成/聚合復(fù)用原則就是在一個(gè)新的對(duì)象里面使用一些已有的對(duì)象,使之成為新對(duì)象的一部分;新的對(duì)象通過向這些對(duì)象的委派達(dá)到復(fù)用已有功能的目的。它的設(shè)計(jì)原則是;要盡量使用合成/聚合,盡量不要使用繼承。
就是說要少用繼承,多用合成關(guān)系來實(shí)現(xiàn)。我曾經(jīng)這樣寫過程序:有幾個(gè)類要與數(shù)據(jù)庫打交道,就寫了一個(gè)數(shù)據(jù)庫操作的類,然后別的跟數(shù)據(jù)庫打交道的類都繼承這個(gè)。結(jié)果后來,我修改了數(shù)據(jù)庫操作類的一個(gè)方法,各個(gè)類都需要改動(dòng)。"牽一發(fā)而動(dòng)全身"!面向?qū)ο笫且巡▌?dòng)限制在盡量小的范圍。
在Java中,應(yīng)盡量針對(duì)Interface編程,而非實(shí)現(xiàn)類。這樣,更換子類不會(huì)影響調(diào)用它方法的代碼。要讓各個(gè)類盡可能少的跟別人聯(lián)系,"不要與陌生人說話"。這樣,城門失火,才不至于殃及池魚。擴(kuò)展性和維護(hù)性才能提高
基本模式
綜述
設(shè)計(jì)模式分為三種類型,共23種。
創(chuàng)建型模式:?jiǎn)卫J健⒊橄蠊S模式、建造者模式、工廠模式、原型模式。
結(jié)構(gòu)型模式:適配器模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式。
行為型模式:模版方法模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式(Interpreter模式)、狀態(tài)模式、策略模式、職責(zé)鏈模式、訪問者模式。
按字典序排列簡(jiǎn)介如下。
Abstract Factory(抽象工廠模式):提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無需指定它們具體的類。
Adapter(適配器模式):將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
Bridge(橋接模式):將抽象部分與它的實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。
Builder(建造者模式):將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
Chain of Responsibility(職責(zé)鏈模式):為解除請(qǐng)求的發(fā)送者和接收者之間耦合,而使多個(gè)對(duì)象都有機(jī)會(huì)處理這個(gè)請(qǐng)求。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理它。
Command(命令模式):將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可取消的操作。
Composite(組合模式):將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。它使得客戶對(duì)單個(gè)對(duì)象和復(fù)合對(duì)象的使用具有一致性。
Decorator(裝飾模式):動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就擴(kuò)展功能而言,它比生成子類方式更為靈活。
Facade(外觀模式):為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,F(xiàn)acade模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。
Factory Method(工廠模式):定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定將哪一個(gè)類實(shí)例化。Factory Method使一個(gè)類的實(shí)例化延遲到其子類。
Flyweight(享元模式):運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。
Interpreter(解析器模式):給定一個(gè)語言,定義它的文法的一種表示,并定義一個(gè)解釋器,該解釋器使用該表示來解釋語言中的句子。
Iterator(迭代器模式):提供一種方法順序訪問一個(gè)聚合對(duì)象中各個(gè)元素,而又不需暴露該對(duì)象的內(nèi)部表示。
Mediator(中介模式):用一個(gè)中介對(duì)象來封裝一系列的對(duì)象交互。中介者使各對(duì)象不需要顯式地相互引用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。
Memento(備忘錄模式):在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣以后就可將該對(duì)象恢復(fù)到保存的狀態(tài)。
Observer(觀察者模式):定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,以便當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并自動(dòng)刷新。
Prototype(原型模式):用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過拷貝這個(gè)原型來創(chuàng)建新的對(duì)象。
Proxy(代理模式):為其他對(duì)象提供一個(gè)代理以控制對(duì)這個(gè)對(duì)象的訪問。
Singleton(單例模式):保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。單例模式是最簡(jiǎn)單的設(shè)計(jì)模式之一,但是對(duì)于Java的開發(fā)者來說,它卻有很多缺陷。在九月的專欄中,David Geary探討了單例模式以及在面對(duì)多線程(multi-threading)、類裝載器(class loaders)和序列化(serialization)時(shí)如何處理這些缺陷。
State(狀態(tài)模式):允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為。對(duì)象看起來似乎修改了它所屬的類。
Strategy(策略模式):定義一系列的算法,把它們一個(gè)個(gè)封裝起來,并且使它們可相互替換。本模式使得算法的變化可獨(dú)立于使用它的客戶。
Template Method(模板方法模式):定義一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類中。Template Method使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
Visitor(訪問者模式):表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
從下一節(jié)開始,詳細(xì)描述以下每一種設(shè)計(jì)模式。
工廠模式
意圖
定義一個(gè)用于創(chuàng)建對(duì)象的接口,讓子類決定實(shí)例化哪一個(gè)類。Factory Method 使一個(gè)類的實(shí)例化延遲到其子類。
適用性
當(dāng)一個(gè)類不知道它所必須創(chuàng)建的對(duì)象的類的時(shí)候。
當(dāng)一個(gè)類希望由它的子類來指定它所創(chuàng)建的對(duì)象的時(shí)候。
當(dāng)類將創(chuàng)建對(duì)象的職責(zé)委托給多個(gè)幫助子類中的某一個(gè),并且你希望將哪一個(gè)幫助子類是代理者這一信息局部化的時(shí)候。
抽象工廠模式
意圖
提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而無需指定它們具體的類。
適用性
一個(gè)系統(tǒng)要獨(dú)立于它的產(chǎn)品的創(chuàng)建、組合和表示時(shí)。
一個(gè)系統(tǒng)要由多個(gè)產(chǎn)品系列中的一個(gè)來配置時(shí)。
當(dāng)你要強(qiáng)調(diào)一系列相關(guān)的產(chǎn)品對(duì)象的設(shè)計(jì)以便進(jìn)行聯(lián)合使用時(shí)。
當(dāng)你提供一個(gè)產(chǎn)品類庫,而只想顯示它們的接口而不是實(shí)現(xiàn)時(shí)。
建造者模式
意圖
將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
適用性
當(dāng)創(chuàng)建復(fù)雜對(duì)象的算法應(yīng)該獨(dú)立于該對(duì)象的組成部分以及它們的裝配方式時(shí)。
當(dāng)構(gòu)造過程必須允許被構(gòu)造的對(duì)象有不同的表示時(shí)。
原型模式
意圖
用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并且通過拷貝這些原型創(chuàng)建新的對(duì)象。
適用性
當(dāng)要實(shí)例化的類是在運(yùn)行時(shí)刻指定時(shí),例如,通過動(dòng)態(tài)裝載;或者
為了避免創(chuàng)建一個(gè)與產(chǎn)品類層次平行的工廠類層次時(shí);或者
當(dāng)一個(gè)類的實(shí)例只能有幾個(gè)不同狀態(tài)組合中的一種時(shí)。建立相應(yīng)數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實(shí)例化該類更方便一些。
單例模式
意圖
保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
適用性
當(dāng)類只能有一個(gè)實(shí)例而且客戶可以從一個(gè)眾所周知的訪問點(diǎn)訪問它時(shí)。
當(dāng)這個(gè)唯一實(shí)例應(yīng)該是通過子類化可擴(kuò)展的,并且客戶應(yīng)該無需更改代碼就能使用一個(gè)擴(kuò)展的實(shí)例時(shí)。
適配器模式
意圖
將一個(gè)類的接口轉(zhuǎn)換成另外一個(gè)客戶希望的接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作。
適用性
你想使用一個(gè)已經(jīng)存在的類,而它的接口不符合你的需求。
你想創(chuàng)建一個(gè)可以復(fù)用的類,該類可以與其他不相關(guān)的類或不可預(yù)見的類(即那些接口可能不一定兼容的類)協(xié)同工作。
(僅適用于對(duì)象Adapter)你想使用一些已經(jīng)存在的子類,但是不可能對(duì)每一個(gè)都進(jìn)行子類化以匹配它們的接口。對(duì)象適配器可以適配它的父類接口。
橋接模式
意圖
將抽象部分與它的實(shí)現(xiàn)部分分離
,使它們都可以獨(dú)立地變化。
適用性
你不希望在抽象和它的實(shí)現(xiàn)部分之間有一個(gè)固定的綁定關(guān)系。例如這種情況可能是因?yàn)?,在程序運(yùn)行時(shí)刻實(shí)現(xiàn)部分應(yīng)可以被選擇或者切換。
類的抽象以及它的實(shí)現(xiàn)都應(yīng)該可以通過生成子類的方法加以擴(kuò)充。這時(shí)B r i d g e 模式使你可以對(duì)不同的抽象接口和實(shí)現(xiàn)部分進(jìn)行組合,并分別對(duì)它們進(jìn)行擴(kuò)充。
對(duì)一個(gè)抽象的實(shí)現(xiàn)部分的修改應(yīng)對(duì)客戶不產(chǎn)生影響,即客戶的代碼不必重新編譯。
(C++)你想對(duì)客戶完全隱藏抽象的實(shí)現(xiàn)部分。在C++中,類的表示在類接口中是可見的。
有許多類要生成。這樣一種類層次結(jié)構(gòu)說明你必須將一個(gè)對(duì)象分解成兩個(gè)部分。Rumbaugh稱這種類層次結(jié)構(gòu)為“嵌套的普化”(nested generalizations )。
你想在多個(gè)對(duì)象間共享實(shí)現(xiàn)(可能使用引用計(jì)數(shù)),但同時(shí)要求客戶并不知道這一點(diǎn)。一個(gè)簡(jiǎn)單的例子便是Coplien的String類,在這個(gè)類中多個(gè)對(duì)象可以共享同一個(gè)字符串表示(StringRep)。
組合模式
意圖
將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。C o m p o s i t e 使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
適用性
你想表示對(duì)象的部分—整體層次結(jié)構(gòu)。
你希望用戶忽略組合對(duì)象與單個(gè)對(duì)象的不同,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象。
裝飾模式
意圖
動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來說,Decorator模式相比生成子類更為靈活。
適用性
在不影響其他對(duì)象的情況下,以動(dòng)態(tài)、透明的方式給單個(gè)對(duì)象添加職責(zé)。
處理那些可以撤消的職責(zé)。
當(dāng)不能采用生成子類的方法進(jìn)行擴(kuò)充時(shí)。一種情況是,可能有大量獨(dú)立的擴(kuò)展,為支持每一種組合將產(chǎn)生大量的子類,使得子類數(shù)目呈爆炸性增長(zhǎng)。另一種情況可能是因?yàn)轭惗x被隱藏,或類定義不能用于生成子類。
門面模式
意圖
為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,F(xiàn)acade模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。
適用性
當(dāng)你要為一個(gè)復(fù)雜子系統(tǒng)提供一個(gè)簡(jiǎn)單接口時(shí)。子系統(tǒng)往往因?yàn)椴粩嘌莼兊迷絹碓綇?fù)雜。大多數(shù)模式使用時(shí)都會(huì)產(chǎn)生更多更小的類。這使得子系統(tǒng)更具可重用性,也更容易對(duì)子系統(tǒng)進(jìn)行定制,但這也給那些不需要定制子系統(tǒng)的用戶帶來一些使用上的困難。Facade可以提供一個(gè)簡(jiǎn)單的缺省視圖,這一視圖對(duì)大多數(shù)用戶來說已經(jīng)足夠,而那些需要更多的可定制性的用戶可以越過Facade層。
客戶程序與抽象類的實(shí)現(xiàn)部分之間存在著很大的依賴性。引入Facade將這個(gè)子系統(tǒng)與客戶以及其他的子系統(tǒng)分離,可以提高子系統(tǒng)的獨(dú)立性和可移植性。
當(dāng)你需要構(gòu)建一個(gè)層次結(jié)構(gòu)的子系統(tǒng)時(shí),使用門面模式定義子系統(tǒng)中每層的入口點(diǎn)。如果子系統(tǒng)之間是相互依賴的,你可以讓它們僅通過Facade進(jìn)行通訊,從而簡(jiǎn)化了它們之間的依賴關(guān)系。
享元模式
意圖
運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對(duì)象。
適用性
一個(gè)應(yīng)用程序使用了大量的對(duì)象。
完全由于使用大量的對(duì)象,造成很大的存儲(chǔ)開銷。
對(duì)象的大多數(shù)狀態(tài)都可變?yōu)橥獠繝顟B(tài)。
如果刪除對(duì)象的外部狀態(tài),那么可以用相對(duì)較少的共享對(duì)象取代很多組對(duì)象。
應(yīng)用程序不依賴于對(duì)象標(biāo)識(shí)。由于Flyweight對(duì)象可以被共享,對(duì)于概念上明顯有別的對(duì)象,標(biāo)識(shí)測(cè)試將返回真值。
代理模式
意圖
為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。
適用性
在需要用比較通用和復(fù)雜的對(duì)象指針代替簡(jiǎn)單的指針的時(shí)候,使用Proxy模式。下面是一些可以使用Proxy模式常見情況:
遠(yuǎn)程代理(Remote Proxy)為一個(gè)對(duì)象在不同的地址空間提供局部代表。
虛代理(Virtual Proxy)根據(jù)需要?jiǎng)?chuàng)建開銷很大的對(duì)象。
保護(hù)代理(Protection Proxy)控制對(duì)原始對(duì)象的訪問。保護(hù)代理用于對(duì)象應(yīng)該有不同的訪問權(quán)限的時(shí)候。
智能指引(Smart Reference)取代了簡(jiǎn)單的指針,它在訪問對(duì)象時(shí)執(zhí)行一些附加操作。它的典型用途包括:
職責(zé)鏈模式
意圖
使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理它為止。
適用性
有多個(gè)的對(duì)象可以處理一個(gè)請(qǐng)求,哪個(gè)對(duì)象處理該請(qǐng)求運(yùn)行時(shí)刻自動(dòng)確定。
你想在不明確指定接收者的情況下,向多個(gè)對(duì)象中的一個(gè)提交一個(gè)請(qǐng)求。
可處理一個(gè)請(qǐng)求的對(duì)象集合應(yīng)被動(dòng)態(tài)指定。
命令模式
意圖
將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化;對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可取消的操作
適用性
像上面討論的MenuItem對(duì)象那樣,抽象出待執(zhí)行的動(dòng)作以參數(shù)化某對(duì)象。你可用過程語言中的回調(diào)(callback)函數(shù)表達(dá)這種參數(shù)化機(jī)制。所謂回調(diào)函數(shù)是指函數(shù)先在某處注冊(cè),而它將在稍后某個(gè)需要的時(shí)候被調(diào)用。Command模式是回調(diào)機(jī)制的一個(gè)面向?qū)ο蟮奶娲贰?/p>
在不同的時(shí)刻指定、排列和執(zhí)行請(qǐng)求。一個(gè)Command對(duì)象可以有一個(gè)與初始請(qǐng)求無關(guān)的生存期。如果一個(gè)請(qǐng)求的接收者可用一種與地址空間無關(guān)的方式表達(dá),那么就可將負(fù)責(zé)該請(qǐng)求的命令對(duì)象傳送給另一個(gè)不同的進(jìn)程并在那兒實(shí)現(xiàn)該請(qǐng)求。
支持取消操作。Command的Execute操作可在實(shí)施操作前將狀態(tài)存儲(chǔ)起來,在取消操作時(shí)這個(gè)狀態(tài)用來消除該操作的影響。Command接口必須添加一個(gè)Execute操作,該操作取消上一次Execute調(diào)用的效果。執(zhí)行的命令被存儲(chǔ)在一個(gè)歷史列表中??赏ㄟ^向后和向前遍歷這一列表并分別調(diào)用Unexecute和Execute來實(shí)現(xiàn)重?cái)?shù)不限的“取消”和“重做”。
支持修改日志,這樣當(dāng)系統(tǒng)崩潰時(shí),這些修改可以被重做一遍。在Command接口中添加裝載操作和存儲(chǔ)操作,可以用來保持變動(dòng)的一個(gè)一致的修改日志。從崩潰中恢復(fù)的過程包括從磁盤中重新讀入記錄下來的命令并用Execute操作重新執(zhí)行它們。
用構(gòu)建在原語操作上的高層操作構(gòu)造一個(gè)系統(tǒng)。這樣一種結(jié)構(gòu)在支持事務(wù)(Transaction)的信息系統(tǒng)中很常見。一個(gè)事務(wù)封裝了對(duì)數(shù)據(jù)的一組變動(dòng)。Command模式提供了對(duì)事務(wù)進(jìn)行建模的方法。Command有一個(gè)公共的接口,使得你可以用同一種方式調(diào)用所有的事務(wù)。同時(shí)使用該模式也易于添加新事務(wù)以擴(kuò)展系統(tǒng)。
解析器模式
意圖
給定一個(gè)語言,定義它的文法的一種表示,并定義一個(gè)解釋器,這個(gè)解釋器使用該表示來解釋語言中的句子。
適用性
當(dāng)有一個(gè)語言需要解釋執(zhí)行,并且你可將該語言中的句子表示為一個(gè)抽象語法樹時(shí),可使用解釋器模式。而當(dāng)存在以下情況時(shí)該模式效果最好:
迭代器模式
意圖
提供一種方法順序訪問一個(gè)聚合對(duì)象中各個(gè)元素,而又不需暴露該對(duì)象的內(nèi)部表示。
適用性
訪問一個(gè)聚合對(duì)象的內(nèi)容而無需暴露它的內(nèi)部表示。
支持對(duì)聚合對(duì)象的多種遍歷。
為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口(即支持多態(tài)迭代)。
中介模式
意圖
用一個(gè)中介對(duì)象來封裝一系列的對(duì)象交互。中介者使各對(duì)象不需要顯式地相互引用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互。
適用性
一組對(duì)象以定義良好但是復(fù)雜的方式進(jìn)行通信。產(chǎn)生的相互依賴關(guān)系結(jié)構(gòu)混亂且難以理解。
一個(gè)對(duì)象引用其他很多對(duì)象并且直接與這些對(duì)象通信,導(dǎo)致難以復(fù)用該對(duì)象。
想定制一個(gè)分布在多個(gè)類中的行為,而又不想生成太多的子類。
備忘錄模式
意圖
在不破壞封裝性的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài),并在該對(duì)象之外保存這個(gè)狀態(tài)。這樣以后就可將該對(duì)象恢復(fù)到保存的狀態(tài)。
適用性
必須保存一個(gè)對(duì)象在某一個(gè)時(shí)刻的 - 部分狀態(tài),這樣以后需要時(shí)它才能恢復(fù)到先前的狀態(tài)。
如果一個(gè)用接口來讓其它對(duì)象直接得到這些狀態(tài),將會(huì)暴露對(duì)象的實(shí)現(xiàn)細(xì)節(jié)并破壞對(duì)象的封裝性。
觀察者模式
意圖
定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新。
適用性
當(dāng)一個(gè)抽象模型有兩個(gè)方面,其中一個(gè)方面依賴于另一方面。將這二者封裝在獨(dú)立的對(duì)象中以使它們可以各自獨(dú)立地改變和復(fù)用。
當(dāng)對(duì)一個(gè)對(duì)象的改變需要同時(shí)改變其它對(duì)象,不知道具體有多少對(duì)象有待改變。
當(dāng)一個(gè)對(duì)象必須通知其它對(duì)象,而它又不能假定其它對(duì)象是誰。換言之,你不希望這些對(duì)象是緊密耦合的。
狀態(tài)模式
意圖
允許一個(gè)對(duì)象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為。對(duì)象看起來似乎修改了它的類。
適用性
一個(gè)對(duì)象的行為取決于它的狀態(tài),并且它必須在運(yùn)行時(shí)刻根據(jù)狀態(tài)改變它的行為。
一個(gè)操作中含有龐大的多分支的條件語句,且這些分支依賴于該對(duì)象的狀態(tài)。這個(gè)狀態(tài)通常用一個(gè)或多個(gè)枚舉常量表示。通常,有多個(gè)操作包含這一相同的條件結(jié)構(gòu)。State模式模式將每一個(gè)條件分支放入一個(gè)獨(dú)立的類中。這使得你可以要所對(duì)象自身的情況將對(duì)象的狀態(tài)作為一個(gè)對(duì)象,這一對(duì)象可以不依賴于其他對(duì)象而獨(dú)立變化。
策略模式
意圖
定義一系列的算法,把它們一個(gè)個(gè)封裝起來,并且使它們可相互替換。本模式使得算法可獨(dú)立于使用它的客戶而變化。
適用性
許多相關(guān)的類僅僅是行為有異。“策略”提供了一種用多個(gè)行為中的一個(gè)行為來配置一個(gè)類的方法。
需要使用一個(gè)算法的不同變體。例如,你可能會(huì)定義一些反映不同的空間/時(shí)間權(quán)衡的算法。當(dāng)這些變體實(shí)現(xiàn)為一個(gè)算法的類層次時(shí),可以使用策略模式。
算法使用客戶不應(yīng)該知道的數(shù)據(jù)??墒褂貌呗阅J揭员苊獗┞稄?fù)雜的、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)。
一個(gè)類定義了多種行為,并且這些行為在這個(gè)類的操作中以多個(gè)條件語句的形式出現(xiàn)。將相關(guān)的條件分支移入它們各自的Strategy類中以代替這些條件語句。
模版模式
意圖
定義一個(gè)操作中的算法的骨架,而將一些步驟延遲到子類中。Te m p l a t e M e t h o d 使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟。
適用性
一次性實(shí)現(xiàn)一個(gè)算法的不變的部分,并將可變的行為留給子類來實(shí)現(xiàn)。
各子類中公共的行為應(yīng)被提取出來并集中到一個(gè)公共父類中以避免代碼重復(fù)。這是Opdyke和Johnson所描述過的“重分解以一般化”的一個(gè)很好的例子。首先識(shí)別現(xiàn)有代碼中的不同之處,并且將不同之處分離為新的操作。最后,用一個(gè)調(diào)用這些新的操作的模板方法來替換這些不同的代碼。
控制子類擴(kuò)展。模板方法只在特定點(diǎn)調(diào)用“hook”操作,這樣就只允許在這些點(diǎn)進(jìn)行擴(kuò)展。
訪問者模式
意圖
表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
適用性
一個(gè)對(duì)象結(jié)構(gòu)包含很多類對(duì)象,它們有不同的接口,而你想對(duì)這些對(duì)象實(shí)施一些依賴于其具體類的操作。
需要對(duì)一個(gè)對(duì)象結(jié)構(gòu)中的對(duì)象進(jìn)行很多不同的并且不相關(guān)的操作,而你想避免讓這些操作“污染”這些對(duì)象的類。Visitor使得你可以將相關(guān)的操作集中起來定義在一個(gè)類中。當(dāng)該對(duì)象結(jié)構(gòu)被很多應(yīng)用共享時(shí),用Visitor模式讓每個(gè)應(yīng)用僅包含需要用到的操作。
定義對(duì)象結(jié)構(gòu)的類很少改變,但經(jīng)常需要在此結(jié)構(gòu)上定義新的操作。改變對(duì)象結(jié)構(gòu)類需要重定義對(duì)所有訪問者的接口,這可能需要很大的代價(jià)。如果對(duì)象結(jié)構(gòu)類經(jīng)常改變,那么可能還是在這些類中定義這些操作較好。
設(shè)計(jì)步驟
綜述
如何把設(shè)計(jì)模式的采用和日益臨近的最后期限、緊縮的預(yù)算和很多公司現(xiàn)有的有限團(tuán)隊(duì)資源相結(jié)合?以下是成功制訂設(shè)計(jì)模式的步驟。
強(qiáng)大的通信和培訓(xùn)
許多機(jī)構(gòu)擁有領(lǐng)先技術(shù),可能正式通過了設(shè)計(jì)師論壇的論證或者非正式的公認(rèn)專家。這些領(lǐng)先廠商將推廣設(shè)計(jì)模式采用中的開放通信,并將培訓(xùn)開發(fā)具體設(shè)計(jì)模式的團(tuán)隊(duì)。通信應(yīng)當(dāng)跨開發(fā)團(tuán)隊(duì)和項(xiàng)目以便預(yù)先防止采用豎井和多種惟一的實(shí)現(xiàn)(謹(jǐn)記每個(gè)Developer/Project AntiPattern的實(shí)現(xiàn))。培訓(xùn)可以采用正式的internal lunch-and-learns、正式的internal class或者派一些員工參加外部培訓(xùn)。這些培訓(xùn)方式將促進(jìn)正確的設(shè)計(jì)模式應(yīng)用程序。如果僅有極少的觀眾能夠參加培訓(xùn),最佳的候選人是那些感覺適合在回來后能夠培訓(xùn)其同事的人。
設(shè)計(jì)模式采用指導(dǎo)
設(shè)計(jì)模式可用于使項(xiàng)目受益,但是他們也可能因?yàn)檎`用而對(duì)應(yīng)用程序造成損害。應(yīng)當(dāng)鼓勵(lì)采用他們,但是對(duì)其的采用應(yīng)當(dāng)受到審閱和驗(yàn)證。設(shè)計(jì)模式可以包含在設(shè)計(jì)和開發(fā)過程中。在任何一種情況中,設(shè)計(jì)模式的使用應(yīng)當(dāng)由審閱者確認(rèn)和驗(yàn)證。在審閱過程中還可能會(huì)遇到這樣的情況,額外的設(shè)計(jì)模式不適用于最初包括的地方。即使環(huán)境中沒有進(jìn)行正式的審閱,這一步驟也可以通過同事審閱或者團(tuán)隊(duì)討論來完成。這一步驟中的審閱者要么是主要團(tuán)隊(duì)的成員,要么與他們建立開放通信。
指導(dǎo)采用對(duì)于broad exposure類別的設(shè)計(jì)模式非常關(guān)鍵。這些設(shè)計(jì)模式具有很多相關(guān)的風(fēng)險(xiǎn),因?yàn)樗麄儗?chuàng)建依賴性。這些依賴性可能在一些對(duì)象類中,例如,只工作在更加廣泛的DAO設(shè)計(jì)模式實(shí)現(xiàn)范圍中的數(shù)據(jù)訪問對(duì)象(DAO)、或者跨應(yīng)用程序邊界(如使用Value Object設(shè)計(jì)模式在應(yīng)用程序和應(yīng)用程序?qū)又g傳輸數(shù)據(jù))。這些設(shè)計(jì)模式也可以由項(xiàng)目中的其他人或者不同項(xiàng)目的人實(shí)現(xiàn),而且實(shí)現(xiàn)應(yīng)當(dāng)重新使用,不同于創(chuàng)建另一種獨(dú)特的實(shí)現(xiàn)。
重用實(shí)現(xiàn),不只是設(shè)計(jì)模式
只要在創(chuàng)建自己的設(shè)計(jì)模式實(shí)現(xiàn)中有一定的滿足,團(tuán)隊(duì)和公司就可以在重用發(fā)生在代碼層時(shí),而不是設(shè)計(jì)創(chuàng)意層時(shí)獲得更多益處。使企業(yè)獲益的最初設(shè)計(jì)模式是改進(jìn)的實(shí)現(xiàn)。但是,真正的目標(biāo)是重用實(shí)現(xiàn)。重用實(shí)現(xiàn)將導(dǎo)致:a其他可重用的類(取決于公共實(shí)現(xiàn));b縮短開發(fā)時(shí)間和降低成本;c縮短維護(hù)時(shí)間和降低成本;d在應(yīng)用程序之間和內(nèi)部輕松集成。
這種重用對(duì)broad exposure設(shè)計(jì)模式非常重要(有時(shí)是基本的)。這些設(shè)計(jì)模式創(chuàng)建了外部依賴性(集成將從公共實(shí)現(xiàn)中受益)或者產(chǎn)生全部的自定義類庫(如果有公共基礎(chǔ)將可重用)。isolated use設(shè)計(jì)模式也可以從重用中獲益,但是如果他們是根據(jù)具體情況定制的,他們就非常難以重用。
有時(shí)您可能會(huì)問自己:“如果重用比較好,為什么設(shè)計(jì)模式和可以重用的實(shí)現(xiàn)不可以一同應(yīng)用呢?”在我們討論設(shè)計(jì)模式如何使更多讀者獲益的時(shí)候才會(huì)討論這個(gè)問題。如果可能,如果已經(jīng)預(yù)定義了實(shí)現(xiàn),那么達(dá)到廣泛適用性這個(gè)目標(biāo)就會(huì)非常困難。然而,一旦設(shè)計(jì)模式被應(yīng)用到特殊的問題域或者技術(shù)基礎(chǔ)設(shè)施中,那么就可以重用在該環(huán)境中產(chǎn)生的實(shí)現(xiàn)。
架構(gòu)中的設(shè)計(jì)模式
這看起來像是一件可怕的任務(wù),需要掌握設(shè)計(jì)模式如何應(yīng)用在實(shí)際情況中,如何構(gòu)建優(yōu)質(zhì)的實(shí)現(xiàn),以及如何促進(jìn)重用實(shí)現(xiàn)。完成該任務(wù)的方法之一就是在環(huán)境中引入應(yīng)用程序架構(gòu)。應(yīng)用程序架構(gòu)提供了應(yīng)用程序需要的結(jié)構(gòu),從而使開發(fā)團(tuán)隊(duì)可以關(guān)注應(yīng)用程序的域邏輯。這包含了已實(shí)現(xiàn)的設(shè)計(jì)模式。除了重用設(shè)計(jì)模式概念或者單個(gè)實(shí)現(xiàn)之外,可以在多個(gè)項(xiàng)目和應(yīng)用程序之間重用架構(gòu)。這種共享的公共實(shí)現(xiàn)確保了兼容性,并為開發(fā)和維護(hù)多種不同的實(shí)現(xiàn)提供了一種低成本替代方案。兼容性提供了重新使用需要的技術(shù)基礎(chǔ)。沒有足夠的篇幅在這里深入討論架構(gòu)的其他重要品質(zhì),如運(yùn)行時(shí)監(jiān)測(cè)和管理、可配置應(yīng)用程序邏輯和適應(yīng)性行為等。您可以從Carnegie Mellon Software Engineering Institute 中學(xué)習(xí)到更多有關(guān)架構(gòu)的知識(shí)。
四要素
綜述
設(shè)計(jì)模式使人們可以更加簡(jiǎn)單方便地復(fù)用成功的設(shè)計(jì)和體系結(jié)構(gòu)。將已證實(shí)的技術(shù)表述成設(shè)計(jì)模式也會(huì)使新系統(tǒng)開發(fā)者更加容易理解其設(shè)計(jì)思路。
模式名稱(pattern name)
一個(gè)助記名,它用一兩個(gè)詞來描述模式的問題、解決方案和效果。命名一個(gè)新的模式增加了我們的設(shè)計(jì)詞匯。設(shè)計(jì)模式允許我們?cè)谳^高的抽象層次上進(jìn)行設(shè)計(jì)。基于一個(gè)模式詞匯表,我們自己以及同事之間就可以討論模式并在編寫文檔時(shí)使用它們。模式名可以幫助我們思考,便于我們與其他人交流設(shè)計(jì)思想及設(shè)計(jì)結(jié)果。找到恰當(dāng)?shù)哪J矫彩俏覀冊(cè)O(shè)計(jì)模式編目工作的難點(diǎn)之一。
問題 - problem
描述了應(yīng)該在何時(shí)使用模式。它解釋了設(shè)計(jì)問題和問題存在的前因后果,它可能描述了特定的設(shè)計(jì)問題,如怎樣用對(duì)象表示算法等。也可能描述了導(dǎo)致不靈活設(shè)計(jì)的類或?qū)ο蠼Y(jié)構(gòu)。有時(shí)候,問題部分會(huì)包括使用模式必須滿足的一系列先決條件。
解決方案 - solution
描述了設(shè)計(jì)的組成成分,它們之間的相互關(guān)系及各自的職責(zé)和協(xié)作方式。因?yàn)槟J骄拖褚粋€(gè)模板,可應(yīng)用于多種不同場(chǎng)合,所以解決方案并不描述一個(gè)特定而具體的設(shè)計(jì)或?qū)崿F(xiàn),而是提供設(shè)計(jì)問題的抽象描述和怎樣用一個(gè)具有一般意義的元素組合(類或?qū)ο蠼M合)來解決這個(gè)問題。
效果 - consequences
描述了模式應(yīng)用的效果及使用模式應(yīng)權(quán)衡的問題。盡管我們描述設(shè)計(jì)決策時(shí),并不總提到模式效果,但它們對(duì)于評(píng)價(jià)設(shè)計(jì)選擇和理解使用模式的代價(jià)及好處具有重要意義。軟件效果大多關(guān)注對(duì)時(shí)間和空間的衡量,它們也表述了語言和實(shí)現(xiàn)問題。因?yàn)閺?fù)用是面向?qū)ο笤O(shè)計(jì)的要素之一,所以模式效果包括它對(duì)系統(tǒng)的靈活性、擴(kuò)充性或可移植性的影響,顯式地列出這些效果對(duì)理解和評(píng)價(jià)這些模式很有幫助。
四人幫
Go F(“四人幫”,又稱Gang of Four,即Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides四人)的《設(shè)計(jì)模式》,原名《Design Patterns: Elements of Reusable Object-Oriented Software》(1995年出版,出版社:Addison Wesly Longman.Inc),第一次將設(shè)計(jì)模式提升到理論高度,并將之規(guī)范化。該書提出了23種基本設(shè)計(jì)模式。時(shí)至今日,在可復(fù)用面向?qū)ο筌浖陌l(fā)展過程中,新的設(shè)計(jì)模式仍然不斷出現(xiàn)。
