設計模式 (電腦)

在軟體工程中，設計模式（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)。
- 實作：這部分應描述實現該模式、該模式的部分方案、實現該模式的可能技術、或者建議實現模式的方法。
- 示例：簡略描繪出如何以程式語言來使用模式。
- 已知應用：業界已知的實作範例。
- 相關模式：這部分包括其他相關模式，以及與其他類似模式的不同。

## 分類

設計模式基於其解決問題的種類而組織成群組。創建型模式創建對象。結構型模式組織類和對象來形成更大的結構從而提供新的功能。行為型模式描述對象之間的協作。

劃分類型｜模式名稱｜描述｜《設計模式》中收錄｜《代碼大全》中提及

創建型模式

抽象工廠｜為一個產品族提供了統一的創建接口。當需要這個產品族的某一系列的時候，可以從抽象工廠中選出相應的系列創建一個具體的工廠類。｜是｜是

工廠方法｜定義一個接口用於創建對象，但是讓子類決定初始化哪個類。工廠方法把一個類的初始化下放到子類。｜是｜是

建造者｜將一個複雜對象的構建與它的表示分離，使得同樣的構建過程可以創建不同的表示。｜是｜否

惰性初始化｜推遲對象的創建、數據的計算等需要耗費較多資源的操作，只有在第一次訪問的時候才執行。｜否｜否

對象池｜通過回收利用對象避免獲取和釋放資源所需的昂貴成本。｜否｜否

原型｜用原型實例指定創建對象的種類，並且通過拷貝這些原型,創建新的對象。｜是｜否

單例｜確保一個類只有一個實例，並提供對該實例的全局訪問。｜是｜是

多例模式｜確保一個類只有命名的實例，並提供對這些實例的全局訪問。｜否｜否

資源獲取為初始化｜通過綁定到合適對象的生命周期來確保資源被適當地釋放。｜否｜否

結構型模式

適配器｜將某個類的接口轉換成客戶端期望的另一個接口表示。適配器模式可以消除由於接口不匹配所造成的類兼容性問題。｜是｜是

橋接｜將一個抽象與實現解耦，以便兩者可以獨立的變化。｜是｜是

合成｜把多個對象組成樹狀結構來表示局部與整體，這樣使用者可以一樣的對待單個對象和對象的組合。｜是｜是

修飾｜向某個對象動態地添加更多的功能。修飾模式是除類繼承外另一種擴展功能的方法。｜是｜是

門面｜為子系統中的一組接口提供一個一致的界面，外觀模式定義了一個高層接口，這個接口使得這一子系統更加容易使用。｜是｜是

享元｜通過共享以便有效的支持大量小顆粒對象。｜是｜否

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

行為型模式

黑板模式｜廣義的觀察者在系統範圍內交流資訊，允許多位讀者和寫者。｜否｜否

責任鏈｜為解除請求的發送者和接收者之間耦合，而使多個對象都有機會處理這個請求。將這些對象連成一條鏈，並沿著這條鏈傳遞該請求，直到有一個對象處理它。｜是｜否

命令｜將一個請求封裝為一個對象，從而使你可用不同的請求對客戶進行參數化；對請求排隊或記錄請求日誌，以及支持可取消的操作。｜是｜否

解釋器｜給定一個語言, 定義它的文法的一種表示，並定義一個解釋器, 該解釋器使用該表示來解釋語言中的句子。｜是｜否

迭代器｜提供一種方法順序訪問一個聚合對象中各個元素, 而又不需暴露該對象的內部表示。｜是｜是

中介者｜包裝了一系列對象相互作用的方式，使得這些對象不必相互明顯作用，從而使它們可以鬆散偶合。當某些對象之間的作用發生改變時，不會立即影響其他的一些對象之間的作用，保證這些作用可以彼此獨立的變化。｜是｜否

備忘錄｜備忘錄對象是一個用來存儲另外一個對象內部狀態的快照的對象。備忘錄模式的用意是在不破壞封裝的條件下，將一個對象的狀態捉住，並外部化，存儲起來，從而可以在將來合適的時候把這個對象還原到存儲起來的狀態。｜是｜否

空對象｜通過提供默認對象來避免空引用。｜否｜是

觀察者｜在對象間定義一個一對多的聯繫性，由此當一個對象改變了狀態，所有其他相關的對象會被通知並且自動刷新。｜是｜是

規格模式｜以布爾形式表示的可重綁定的商業邏輯。｜否｜否

狀態｜讓一個對象在其內部狀態改變的時候，其行為也隨之改變。狀態模式需要對每一個系統可能取得的狀態創立一個狀態類的子類。當系統的狀態變化時，系統便改變所選的子類。｜是｜否

策略｜定義一個演算法的系列，將其各個分裝，並且使他們有交互性。策略模式使得演算法在使用者使用的時候能獨立的改變。｜是｜是

模板方法｜模板方法模式準備一個抽象類，將部分邏輯以具體方法及具體構造子類的形式實現，然後聲明一些抽象方法來迫使子類實現剩餘的邏輯。不同的子類可以以不同的方式實現這些抽象方法，從而對剩餘的邏輯有不同的實現。先構建一個頂級邏輯框架，而將邏輯的細節留給具體的子類去實現。｜是｜是

訪問者｜封裝一些施加於某種數據結構元素之上的操作。一旦這些操作需要修改，接受這個操作的數據結構可以保持不變。訪問者模式適用於數據結構相對未定的系統，它把數據結構和作用於結構上的操作之間的耦合解脫開，使得操作集合可以相對自由的演化。｜是｜否

併發型模式｜主動對象｜它主要是將方法的內容折解為執行本體和請求，在引入並時(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就能避免。｜否｜否

雙重檢查鎖定｜否｜否

守衛掛起模式｜否｜否

會合模式｜否｜否

監測對象｜否｜否

讀寫鎖｜否｜否

調度｜否｜否

線程池｜否｜否

線程特定存儲｜否｜否

反應器｜否｜否

## 參閱

- 設計模式：可復用面向對象軟體的基礎
- 反模式，對某個問題經常出現的、在設計中應該儘量避免的、壞的設計方案。
- 代碼重構
- 內聚性 (電腦科學)
- SOLID (面向對象設計)
- GRASP (物件導向設計)

## 參考資料

- 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