設計模式 (電腦)
在軟件工程中,設計模式(design pattern)是對軟件設計中普遍存在(反覆出現)的各種問題,所提出的解決方案。這個術語是由埃里希·伽瑪(Erich Gamma)等人在1990年代從建築設計領域引入到電腦科學的。
設計模式並不直接用來完成程式碼的編寫,而是描述在各種不同情況下,要怎麼解決問題的一種方案。物件導向設計模式通常以類別或物件來描述其中的關係和相互作用,但不涉及用來完成應用程式的特定類別或物件。設計模式能使不穩定依賴於相對穩定、具體依賴於相對抽象,避免會引起麻煩的緊耦合,以增強軟件設計面對並適應變化的能力。
並非所有的軟件模式都是設計模式,設計模式特指軟件「設計」層次上的問題。還有其他非設計模式的模式,如架構模式。同時,演算法不能算是一種設計模式,因為演算法主要是用來解決計算上的問題,而非設計上的問題。
隨着軟件開發社群對設計模式的興趣日益增長,已經出版了一些相關的專著,定期召開相應的研討會,而且沃德·坎寧安(Ward Cunningham)為此發明了WikiWiki用來交流設計模式的經驗。
發展歷史
建築師克里斯托佛·亞歷山大在1977/79年編制了一本匯集設計模式的書,但是這種設計模式的思想在建築設計領域裏的影響遠沒有後來在軟件開發領域裏傳播的廣泛。
肯特·貝克和沃德·坎寧安在1987年,利用克里斯托佛·亞歷山大在建築設計領域裏的思想開發了設計模式,並把此思想應用在Smalltalk中的圖形用戶介面(GUI)的生成中。一年後,埃里希·伽瑪在他的蘇黎世大學博士畢業論文中開始嘗試把這種思想覆寫為適用於軟件開發。與此同時James Coplien 在1989年至1991年也在利用相同的思想致力於C++的開發,而後於1991年發表了他的著作Advanced C++ Programming Styles and Idioms。同年,埃里希·伽瑪得到了博士學位,然後去了美國,在那與Richard Helm、Ralph Johnson、John Vlissides 合作出版了《設計模式:可復用物件導向軟件的基礎》(Design Patterns - Elements of Reusable Object-Oriented Software) 一書,在此書中共收錄了 23 種設計模式。
這四位作者在軟件開發領域裏以「四人幫」(英語,Gang of Four,簡稱GoF)而聞名,並且他們在此書中的協同運作導致了軟件設計模式的突破。有時,GoF也會用於代指《設計模式》這本書。
表述格式
表述一個軟件設計模式的格式根據作者的不同,劃分和名稱等都會有所不同。常用的GoF描述模式的格式大致分為以下這些部分:
- 模式名:每一個模式都有自己的名字,模式的名字使得我們可以討論我們的設計。
- 問題:在物件導向的系統設計過程中反覆出現的特定場合,它導致我們採用某個模式。
- 解決方案:上述問題的解決方案,其內容給出了設計的各個組成部分,它們之間的關係、職責劃分和協同運作方式。
- 別名:一個模式可以有超過一個以上的名稱。這些名稱應該要在這一節註明。
- 動機:在哪種情況使用該模式,是本節提供的方案(包括問題與來龍去脈)的責任。
- 適用性:模式適用於哪些情況、模式的背景等等。
- 結構:這部分常用類圖與互動圖闡述此模式。
- 參與者:這部分提供一份本模式用到的類與物件清單,與它們在設計下扮演的角色。
- 合作:描述在此模式下,類與物件間的互動。
- 影響:採用該模式對軟件系統其他部分的影響,比如對系統的擴充性、可移植性的影響。影響也包括負面的影響。這部分應描述使用本模式後的結果、副作用、與權衡(trade-off)。
- 實作:這部分應描述實現該模式、該模式的部分方案、實現該模式的可能技術、或者建議實現模式的方法。
- 範例:簡略描繪出如何以程式語言來使用模式。
- 已知應用:業界已知的實作範例。
- 相關模式:這部分包括其他相關模式,以及與其他類似模式的不同。
分類
《設計模式》一書原先把設計模式分為建立型模式、結構型模式、行為型模式,把它們通過授權、聚合、診斷的概念來描述。若想更進一步了解關於物件導向設計的背景,參考介面模式、內聚性。若想更進一步了解關於物件導向程式設計的背景,參考繼承,介面,多型。
劃分類型 | 模式名稱 | 描述 | 《設計模式》中提及 | 《代碼大全》中提及[1] |
---|---|---|---|---|
創建型模式 | ||||
抽象工廠模式 | 為一個產品族提供了統一的建立介面。當需要這個產品族的某一系列的時候,可以從抽象工廠中選出相應的系列建立一個具體的工廠類。 | 是 | 是 | |
工廠方法模式 | 定義一個介面用於建立對象,但是讓子類決定初始化哪個類。工廠方法把一個類的初始化下放到子類。 | 是 | 是 | |
生成器模式 | 將一個複雜對象的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。 | 是 | 否 | |
惰性初始模式 | 推遲對象的建立、數據的計算等需要耗費較多資源的操作,只有在第一次訪問的時候才執行。 | 否 | 否 | |
對象池模式 | 通過回收利用對象避免取得和釋放資源所需的昂貴成本。 | 否 | 否 | |
原型模式 | 用原型實例指定建立對象的種類,並且通過拷貝這些原型,新增的對象。 | 是 | 否 | |
單例模式 | 確保一個類只有一個實例,並提供對該實例的全域訪問。 | 是 | 是 | |
多例模式 | 確保一個類只有命名的實例,並提供對這些實例的全域訪問。 | 否 | 否 | |
資源取得為初始化 | 通過繫結到合適對象的生命周期來確保資源被適當地釋放。 | 否 | 否 | |
結構型模式 | ||||
配接器模式 | 將某個類的介面轉換成客戶端期望的另一個介面表示。配接器模式可以消除由於介面不匹配所造成的類相容性問題。 | 是 | 是 | |
橋接模式 | 將一個抽象與實現解耦,以便兩者可以獨立的變化。 | 是 | 是 | |
組合模式 | 把多個對象組成樹狀結構來表示局部與整體,這樣用戶可以一樣的對待單個對象和對象的組合。 | 是 | 是 | |
修飾模式 | 向某個對象動態地添加更多的功能。修飾模式是除類繼承外另一種擴充功能的方法。 | 是 | 是 | |
外觀模式 | 為子系統中的一組介面提供一個一致的介面, 外觀模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。 | 是 | 是 | |
享元 | 通過共用以便有效的支援大量小顆粒對象。 | 是 | 否 | |
代理 | 為其他對象提供一個代理以控制對這個對象的訪問。 | 是 | 否 | |
行為型模式 | ||||
黑板 | 廣義的觀察者在系統範圍內交流資訊,允許多位讀者和寫者。 | 否 | 否 | |
責任鏈 | 為解除請求的傳送者和接收者之間耦合,而使多個對象都有機會處理這個請求。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它。 | 是 | 否 | |
命令 | 將一個請求封裝為一個對象,從而使你可用不同的請求對客戶進行參數化;對請求排隊或記錄請求紀錄檔,以及支援可取消的操作。 | 是 | 否 | |
直譯器 | 給定一個語言, 定義它的文法的一種表示,並定義一個直譯器, 該直譯器使用該表示來解釋語言中的句子。 | 是 | 否 | |
迭代器 | 提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。 | 是 | 是 | |
中介者 | 包裝了一系列對象相互作用的方式,使得這些對象不必相互明顯作用,從而使它們可以鬆散偶合。當某些對象之間的作用發生改變時,不會立即影響其他的一些對象之間的作用,保證這些作用可以彼此獨立的變化。 | 是 | 否 | |
備忘錄 | 備忘錄對象是一個用來儲存另外一個對象內部狀態的快照的對象。備忘錄模式的用意是在不破壞封裝的條件下,將一個對象的狀態捉住,並外部化,儲存起來,從而可以在將來合適的時候把這個對象還原到儲存起來的狀態。 | 是 | 否 | |
空對象 | 通過提供預設對象來避免空參照。 | 否 | 是 | |
觀察者模式 | 在對象間定義一個一對多的聯絡性,由此當一個對象改變了狀態,所有其他相關的對象會被通知並且自動重新整理。 | 是 | 是 | |
規格 | 以布林形式表示的可重繫結的商業邏輯。 | 否 | 否 | |
狀態 | 讓一個對象在其內部狀態改變的時候,其行為也隨之改變。狀態模式需要對每一個系統可能取得的狀態創立一個狀態類的子類。當系統的狀態變化時,系統便改變所選的子類。 | 是 | 否 | |
策略 | 定義一個演算法的系列,將其各個分裝,並且使他們有互動性。策略模式使得演算法在用戶使用的時候能獨立的改變。 | 是 | 是 | |
模板方法 | 模板方法模式準備一個抽象類,將部分邏輯以具體方法及具體構造子類的形式實現,然後聲明一些抽象方法來迫使子類實現剩餘的邏輯。不同的子類可以以不同的方式實現這些抽象方法,從而對剩餘的邏輯有不同的實現。先構建一個頂級邏輯框架,而將邏輯的細節留給具體的子類去實現。 | 是 | 是 | |
訪問者 | 封裝一些施加於某種數據結構元素之上的操作。一旦這些操作需要修改,接受這個操作的數據結構可以保持不變。訪問者模式適用於數據結構相對未定的系統,它把數據結構和作用於結構上的操作之間的耦合解脫開,使得操作集合可以相對自由的演化。 | 是 | 否 | |
併發型模式 | 主動對象 | 它主要是將方法的內容折解為執行本體和請求,在引入並時(Concurrency)處理時,可透過非同步(asynchronous)處理來達成。
例如:該method 收到request 時,所以這時候caller並不需要在此等待request完成(即為非同步),然後會將其設成active or busy,而後面的request則會進scheduler,request完成時透過其他thread來通知noitfy caller. |
否 | 否 |
阻礙 | 避免在某些狀態不滿足的情形下被執行,因此有點防呆的意思又被稱為(Anti-pattern), 比如你想讀一個ZIP file,當method執行時又去呼叫其他method才發現,該file還未open,這時就會有exception產生,若能在之前就有Balking就能避免。 | 否 | 否 | |
雙重檢查鎖定 | 否 | 否 | ||
守衛 | 否 | 否 | ||
領導者/追隨者 | 否 | 否 | ||
監測對象模式 | 否 | 否 | ||
讀寫鎖 | 否 | 否 | ||
排程 | 否 | 否 | ||
線程池模式 | 否 | 否 | ||
線程特定儲存 | 否 | 否 | ||
反應器 | 否 | 否 |
參閱
參考資料
- ^ McConnell, Steve. Design in Construction. Code Complete 2nd edition. Microsoft Press. June 2004: 104. ISBN 978-0735619678.
Table 5.1 Popular Design Patterns
- Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides: Design Patterns, Addison-Wesley, 1995, hardcover, 395 pages, ISBN 978-0-201-63361-0, Design Patterns CD, 1997 ISBN 978-0-201-63498-3
- Frank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad, Michael Stal: Pattern-oriented Software Architecture, Volume 1: A System of Patterns, John Wiley & Sons Ltd., ISBN 978-0-471-95869-7
- Douglas Schmidt: Pattern-oriented Software Architecture. Volume 2: Patterns for Concurrent and Networked Objects, John Wiley & Sons Ltd., ISBN 978-0-471-60695-6
- Alan Shalloway, James R. Trott: Design Patterns Explained: A New Perspective on Object-Oriented Design, Addison-Wesley, ISBN 978-0-201-71594-1
- Martin Fowler: Patterns of Enterprise Application Architecture, Addison-Wesley, ISBN 978-0-321-12742-6