1. 程式人生 > >好書整理系列之-設計模式:可複用面向物件軟體的基礎 6

好書整理系列之-設計模式:可複用面向物件軟體的基礎 6


第6章結論
或許有人會認為本書並多大貢獻。畢竟,它沒有提出任何前所未見的新演算法或者新程式
設計技術。本書既沒有給出一種嚴格的系統設計方法,也沒有提出一套新的設計理論-它
只是將現有的一些設計加以文件化。也許你會認為它是一本合適的入門指南,但對有經驗的
面向物件設計人員卻並無多大幫助。
我們希望你不會有上面這樣的想法。這是因為對設計模式的分類整理是重要的,它為我
們使用的各種技術提供了標準的名稱和定義。如果我們不研究軟體中的設計模式,就無法對
它們進行改進,更難以提出新的設計模式。
本書僅僅是一個開始。它討論了面向物件設計專家們所使用的某些最常見的設計模式,
而人們常常也會在口頭交談或分析已有系統時聽到和學到這些設計模式。曾有人看了本書的
初稿後也將其使用的設計模式寫下來,因此,本書就更應起到拋磚引玉的作用。我們希望這
將標誌著一場把軟體從業人員專門知識和技能加以文件化運動的開始。
本章的討論內容包括我們認為設計模式將帶來的巨大影響,設計模式與其他設計工作的
關係,以及你怎樣發現和整理設計模式。
6.1 設計模式將帶來什麼
根據我們日常使用設計模式的經驗,我們認為它們將在以下幾個方面影響你設計面向對
象軟體的方式。
6.2 一套通用的設計詞彙
對使用傳統語言的程式設計專家們的研究表明,其知識和經驗並非是簡單地圍繞語法來
組織的,而是圍繞著諸如演算法、資料結構、習慣用語[ A S 8 5 , C o p 9 2 , C u r 8 9 , S S 8 6 ]和滿足某特定
目標的計劃[ S E 8 4 ]等更大的概念結構來組織的。設計者可能考慮得更多的不是用來記錄設計
的表示方式,而是如何把當前的設計問題與已知的計劃、演算法、資料結構和習慣用語等進行
匹配。
電腦科學家們對演算法和資料結構進行命名和分類,但我們卻很少為其他型別的模式命
名。設計模式為設計者們交流討論、書寫文件以及探索各種不同設計提供了一套通用的設計
詞彙。設計模式使你可以在比設計表示或程式語言更高的抽象級別上談論一個系統,從而降
低了其複雜度。設計模式提高了你的設計及你與同事討論這些設計的層次。
一旦你吸收了本書中的各設計模式,你的設計詞彙就幾乎肯定要有所改變。你會直接使
用這些模式的名稱來表示某個設計,比如你會說:“這裡我們使用觀察者模式”,或者,“讓我
們從這些類中抽出一個S t r a t e g y”。
6.3 書寫文件和學習的輔助手段
瞭解本書中的各設計模式可使你更容易理解已有的系統。大多數規模較大的面向物件系
統都使用了這些設計模式。人們在學習面向物件程式設計時常常抱怨系統中繼承的使用令人費解
以及難於理解控制流程。這在很大程度上是由於他們未能理解該系統中的設計模式。學習這
些設計模式將有助於你理解已有的面向物件系統。
這些設計模式也能提高你的設計水平。它們為你提供一些常見問題的解決方案。當然,
如果你長期從事面向物件系統的工作,遲早你也會自己學到這些設計模式。但通過本書你可
以學得更快。學好這些模式將有助於一個新手做出像專家一樣的設計。
而且,按照一個系統所使用的設計模式來描述該系統可以使他人理解起來容易得多,否
則,就必須對該系統的設計進行逆向工程來弄清其使用的設計模式。有一套通用的設計詞彙
的好處是你不必描述整個設計模式,而只要使用它的名字,當他人讀到這個名字就會理解你
的設計。當然如果讀者不知道這個設計模式,他就必須先去查詢學習該模式,即使這樣也還
是比逆向工程來的容易。
我們在自己的設計中使用這些模式,並發現它們有很多好處。我們還以某些可爭議的幼
稚方式使用這些設計模式。我們用它們來為類命名,思考和傳授優秀的設計,並用一連串的
設計模式來描述我們的設計。很容易想出更復雜的使用設計模式的方式,比如基於模式的
C A S E工具或超文字文件。不過即使沒有複雜的工具,設計模式對我們也還是很有幫助的。
6.4 現有方法的一種補充
面向物件設計方法可用來促進良好的設計,教新手如何設計,以及對設計活動進行標準
化。一個設計方法通常定義了一組(常常是圖形化的)用來為設計問題各方面進行建模的記
號(n o t a t i o n),以及決定在什麼樣情況下以什麼樣的方式使用這些記號的一組規則。設計方
法通常描述一個設計中出現的問題,如何解決這些問題,以及如何評估一個設計。但設計方
法還不能描述設計專家的經驗。
我們相信設計模式是面向物件設計方法所缺少的一塊重要內容。這些設計模式展示瞭如
何使用諸如物件、繼承和多型等基本技術。它們也展示瞭如何以演算法、行為、狀態或者需生
成的物件型別來將一個系統引數化。設計模式使你可以更多地描述“為什麼”這樣設計而不
僅僅是記錄你的設計結果。設計模式的適用性、效果和實現部分都會幫助指導你做出各個必
要的設計決定。
設計模式在將一個分析模型轉換為一個實現模型的時候特別有用。儘管許多人聲稱面向
物件分析可以平滑地向設計轉換,但實踐表明遠非如此。一個靈活的可複用的設計常會包含
一些分析模型中沒有的物件。另外,你所使用的程式語言和類庫也會影響設計。因此,為使
設計可複用,常常需要重新設計分析模型。許多設計模式描述了這樣的問題,這也是為什麼
我們稱之為設計模式的原因。
一個成熟的設計方法不僅要有設計模式,還可有其他型別的模式,如分析模式,使用者界
面設計模式,或者效能調節模式等等。但是設計模式是最主要的部分,這在以前卻被忽略了。
6.5 重構的目標
開發可複用軟體的一個問題是開發者常常不得不重新組織或重構[ O J 9 0 ]軟體系統。設計
模式可以幫助你重新組織一個設計,同時還能減少以後的重構工作。
面向物件軟體的生命週期常分為幾個階段。Brain Foote將其分為原型階段、擴充套件階段和


鞏固階段三個階段[ F o o 9 2 ]。
在原型階段,首先建立一個快速原型,在此基礎上進行增量式的修改,直至能滿足一組
基本需求,然後進入“青春期”。此時,軟體中的類層次通常直接反映了原始問題域中的各個
實體。該階段主要的複用方式是通過繼承進行白箱複用。
一旦軟體進入青春期並交付使用,其演化就由以下兩個相互衝突的要求來決定: ( 1 )該軟
件必須滿足更多的需求。( 2 )該軟體必須更易於複用。新的需求常常要求加入新的類和操作甚
至增加整個類層次。於是該軟體就要經過一個擴充套件階段來滿足新的需求。然而,這種擴充套件並
不能持續很久。軟體的不斷擴充套件將使其變得過於滯脹僵硬而難以進一步修改。軟體類層次不
再與任何問題域匹配,而是多個問題域的混合反映,並且類中定義了許多不相關的操作和實
例變數。
該軟體若要繼續演化就必須重新組織,這個過程稱為重構(r e f a c t o r i n g)。框架常常在這
個階段出現。重構工作包括將類拆分為專用和通用的構件,把各個操作在類層次上提或下放
到合適的類中,並使各個類的介面合理化。這個鞏固階段將會產生許多新型別的物件,它們
通常是通過分解而不是繼承原有的物件而得到的。因而黑箱複用代替了白箱複用。滿足更多
需求和達到更高可複用性的要求推動面向物件軟體不斷重複擴充套件和鞏固這兩個階段-擴充套件
以滿足新的需求,而鞏固使軟體更為通用(參見下圖)。
這個迴圈是不可避免的。但好的設計者不僅知道哪些變化會促使重構,而且還知道哪些
類和物件結構能夠避免重構-它們的設計對於需求變化具有健壯性。對需求進行徹底分析
有助於突出在軟體的生命週期中易於發生變化的那些需求,而一個好的設計應對這些變化保
持穩定。
我們的設計模式記錄了許多重構產生的設計結構。在設計初期使用這些模式可以防止以
後的重構。不過你即使是在系統建成以後才瞭解如何使用這些模式,它們仍可以教你如何修
改你的系統。設計模式為你的重構提供了目標。
6.6 本書簡史
分類整理設計模式肇始於E r i c h的博士論文[Gam91, Gam92]的部分工作。他的論文中大約
有佔本書半數的模式。到O O P S L A’9 1召開的時候它已正式成為一項獨立的工作,並且
R i c h a r d已加入進來與E r i c h一道從事這項工作。不久J o h n也加入進來。到O O P S L A’9 2的時候,
R a l p h也已加入到這個小組中。我們曾試圖使我們的工作成果可以發表在E C O O P’9 3上,但
我們很快意識到篇幅太長的論文是不會被錄用的。所以我們將其簡化為一個摘要發表在那次
會議上。在那以後我們決定把我們分類整理的模式寫成一本書。


擴充套件
進一步的複用進一步的需求
生成原型鞏固
在此過程中,我們改動了一些模式的名稱。“Wr a p p e r”變成了“ D e c o r a t o r”,“G l u e”變
成了“F a c a d e”,“S o l i t a i r e”變成了“S i n g l e t o n”,以及“Wa l k e r”變成了“Vi s i t o r”,並刪掉
了幾個看起來不那麼重要的模式。不過自1 9 9 2年以來,這個分類體系中包含哪些模式沒有多
大變化,但各模式本身卻有了巨大改進。
實際上,注意到某些東西是一個模式還是整個工作中相對容易的部分。我們四個人都經
常從事建造面向物件系統的工作,發現當接觸到足夠多的系統時,發現模式並不困難。然而
描述模式卻要困難得多。
當你回過頭來看你已經建好的一些系統時,會發現所做的工作中就存在著模式。但是,
要很好地描述它們以使不熟悉的人也能理解並意識到它們為什麼重要就很困難了。專家們能
立即從我們模式的早期版本中意識到它們的價值,但也只有這些實際已經用過這些模式的人
才能理解它們。
由於本書的主要目的之一在於教設計新手進行面向物件設計,所以我們必須改進模式的
分類描述。我們將每個模式的篇幅進行了擴充,其中加入了較具體的說明動機的例子和示例
程式碼,同時對模式的權衡以及實現模式的不同方式也進行了檢查。這樣就使模式學起來更容
易一些。
在過去的一年中所做的另一個重要修改是更加強調一個模式所針對的問題。模式是問題
的解決方案,是可以被重複使用的技術手段,這很容易明白;困難的是知道在什麼情況下使
用這個模式才是恰當的,也就是要刻畫這個模式所針對的問題及其上下文,只有在這樣的上
下文中,這個模式才是最優解。一般而言,瞭解“做什麼”要比“為什麼”來的容易;而一
個模式的“為什麼”就是它要解決的問題。瞭解一個模式的目的也是重要的,它可以幫助我
們選擇要使用的模式,也可以幫助我們理解已有系統的設計。作為一個模式的作者,即使你
已經知道了解決方案,你還是必須回過頭來確定並刻畫該模式所解決的問題。
6.7 模式界
我們並不是唯一的對寫書來分類整理專家們使用的設計模式感興趣的小組。我們屬於一
個更大的圈子,這個圈子裡的人們對模式特別是有關軟體的模式很感興趣。建築師
Christopher Alexander第一個研究了建築物和社群的模式,並開發了一個“模式語言”來生成
它們。他的工作一次次地啟發了我們。所以有必要將我們的工作與他的工作作一個比較,然
後我們將看看其他有關軟體模式方面的工作。
6.8 Alexander的模式語言
我們的工作在許多方面和A l e x a n d e r的類似。二者都是在觀察已有系統的基礎上,發現其
中的模式,都有描述模式的模板(儘管我們的模板有很大的不同),都是用自然語言和許多例
子而不是用形式語言來描述模式,都給出了每個模式背後的原理。
不過我們的工作也在許多方面不同於A l e x a n d e r的模式語言:
1) 人類從事建築活動已有幾千年的歷史,積累下來許多經典的案例可供參考。相對而言
建造軟體系統的歷史就短的多,很少有系統可稱得上經典。
2) Alexander給出了他的模式的使用順序,而我們沒有。
3) Alexander的模式強調它們所針對的問題,而設計模式則更詳細的描述瞭解決方案。


4 ) A l e x a n d e r聲稱他的模式可以生成完整的建築,而我們不能說我們的模式可以生成完整
的程式。
A l e x a n d e r聲稱可以通過簡單地一個接一個地使用他的模式來設計一所房屋。這類似於一
些面向物件設計方法學家的目標,他們也給出了一步步地進行軟體設計的規則。A l e x a n d e r並
不否認創造的必要性,他的一些模式要求設計者理解所設計建築物的使用者的生活習慣。而
且,他對設計的“詩意”的信仰暗示了存在某種高於模式語言本身的專業水平。不過他對
模式怎樣生成設計的描述卻意味著模式語言可使設計活動成為一種確定的和可重複的過程。
A l e x a n d e r的觀點啟發我們關注設計中的權衡問題-多種“力”共同決定了最終的設計
結果。在他的影響下,我們慎重考慮了我們的設計模式的適用性及其效果。這也使我們不再
試圖定義模式的形式化表示。這是因為儘管這種形式化表示將使模式自動化成為可能,但目
前更重要的是探索新的模式而不是將模式形式化。
依據A l e x a n d e r的觀點,本書的模式不能形成一個模式語言。考慮到人們建造的軟體系統
的多樣性,我們很難給出一個“完備”的模式集合來指導人們一步步地設計出完整的應用。
儘管對於某些特定型別的應用(例如報表生成系統)我們可以做到這一點。然而本書的模式
體系僅僅是相關模式的集合,我們不能視之為一種模式語言。
實際上,我們認為永遠也不會有一個完備的軟體模式語言。當然我們可以使模式系統更
加完整,如可以加入包括框架及其怎樣使用框架[ J o h 9 2 ],使用者介面設計模式[ B J 9 4 ],分析模
式[ C o a 9 2 ],以及軟體開發過程中的其他各個方面內容。設計模式僅僅是一個更大的軟體模式
語言的一部分。
6.9 軟體中的模式
我們第一次集體研究軟體體系結構是在O O P S L A’9 1大會中一次由Bruce Anderson主持的
討論會上。那次討論會致力於為軟體體系結構設計者編寫一本手冊(從本書看來,我們認為
“體系結構百科全書”這個名稱要比“體系結構手冊”更好一些)。此後又舉行了一系列的會
議,最近的一次是1 9 9 4年8月召開的第一屆程式模式語言大會,這次會議建立了一個群體,其
興趣是將軟體經驗文件化。
當然,也有其他人抱有同樣的目標。Danald Knuth的《計算機程式設計的藝術》[ K n u 7 3 ]
就是分類整理軟體知識的最早嘗試之一,只是他著重於描述演算法。事實證明,即便如此,這
項工作也還是工程浩大而難以完成。《Graphics Gems》系列[Gla90, Arv91, Kir92]是另一個同
樣著重於演算法的設計知識分類體系。美國國防部發起的領域專用軟體結構計劃集中收集有關
體系結構方面的資訊。基於知識的軟體工程界試圖一般地表述軟體相關知識。此外還有許多
其他小組在為與我們相似的目標而努力。
James Coplien的《Advanced C++: Programming Styles and Indioms》[ C o p 9 2 ]一書也對我
們產生了影響。相對於我們的設計模式,該書中描述的模式更加針對C + +語言,而且還包含
了許多低層的模式。不過正如在我們的模式中已指出的那樣,二者之間是有一些重複的。J i m
在模式界很活躍,目前他正在研究那些用來描述軟體開發組織中人的角色的模式。
你還可以從其他許多地方找到對模式的描述。Kent Beck 是軟體界中首先倡導學習
Christopher Alexander的工作的先驅者之一。在1 9 9 3年他開始在《The Smalltalk Report》上撰
2 3 6 設計模式:可複用面向物件軟體的基礎

參見“The poetry of the language” [ A I S + 7 7 ]
寫關於S m a l l t a l k模式的一個專欄。Peter Coad開始收集模式也有一段時間了。在我們看來,他
的關於模式的論文主要討論的是分析模式[ C o a 9 2 ]。我們知道他還在繼續從事這方面的工作,
但我們沒有看到他最新的成果。我們也聽說有好幾本關於模式的書正在撰寫之中,但目前一
本也沒有看到,所以我們只能告訴你它們就要出現了。其中有一本書將來源於P a t t e r n
Language of Programming會議。
6.10 邀請參與
如果你對模式感興趣的話,你能做些什麼呢?首先,你可以在你的設計工作中使用這些
設計模式,並尋找其他可用的設計模式。接下來幾年裡將會有許多有關模式的書和文章出現,
所以不愁沒地方找新的模式。不斷積累和使用你的模式詞彙,在與他人討論你的設計時你可
以使用它們,在構思和書寫你的設計時也可以使用它們。
其次,提出你的批評。這個設計模式體系是許多人辛勤工作的成果,除了我們之外,還
有幾十個評論者提出了反饋意見。如果你發現了存在的問題或者覺得某些地方需要進一步解
釋的話,請和我們聯絡。同樣,對於其他模式體系,也請給予你的反饋意見。模式的一個重
要好處在於它提供的設計決策不再是模糊的直覺意向,模式的作者可以明確地說明他在各需
求要素間所作的權衡取捨。這就為發現並與作者討論其模式的不足之處提供了方便。你可以
充分利用模式這個優越性。
再次,尋找你使用過的模式,並把它們寫下來。把它們作為你的文件的組成部分,給別
人看。你並不一定要在研究機構裡才可以發掘模式。實際上,如果你沒有某方面的實踐經驗,
要發現相關的模式幾乎是不可能的。你儘管寫下你的模式體系,但一定要讓其他人來幫助你
使之成形!
6.11 臨別感想
最佳的設計要用到許多設計模式,它們契合交織,形成一個更大的整體。正如C h r i s t o p h e r
A l e x a n d e r所說:
以一種鬆散的方式把一些模式串接在一起來建造建築是可能的。這樣的建築僅僅是
一些模式的堆砌,而不緊湊。這不夠深刻。然而另有一種組合模式的方式,許多模式重
疊在同一個物理空間裡:這樣的建築非常緊湊,在一小塊空間裡集成了許多內涵;由於
這種緊湊,它變得深刻。