# 設計模式(Design pattern)
設計模式該術語源自Erich Gamma等人在上世紀90年代從建筑設計領域引入到計算機科學的(很難想象到底有多大關聯)。它是對軟件設計中一些反復出現,普遍存在的問題所提出的解決方案。所以說設計模式并不是某種語言的某塊代碼,設計模式是一種思想,提供給在編碼時候遇到的各種問題是可以采取的解決方案,更傾向于一種邏輯思維,而不是萬能代碼塊。
設計模式使人可以更加簡單方便的復用一些較為成功的設計和體系結構,使用設計模式來使人理解整個系統的開發思路。
## 設計模式的四要素
**模式名稱(pattern name)**:助記名,以幾個詞來描述問題,解決方案和效果。模式名可以幫助我們思考,一邊與其他程序員進行設計思想交流。
**問題(problem)**:描繪使用設計模式的具體情況。解釋設計問題和問題存在的因果,可能描述特定的設計問題,也可能描述導致不靈活的設計的類或者對象結構等。
**解決方案(solution)**:描述設計的組成成分,它們之間的相互關系與各自的職責和協作方式。解決方案并不具體的描述某種設計的實現,而是提供設計問題的抽象描述和怎樣用一些一般意義的元素來解決這個問題。
**效果(consequences)**:描述模式的應用效果以及使用模式需要權衡的問題,雖然很少提到模式的效果,但是對于評價該模式在該問題下是有很重要的意義。模式效果包括此模式對于系統的靈活性,擴充性或者可移植性的影響,顯示列出這些效果可以客觀的評價該模式對于該問題的適用性。
## 設計模式分類
**創建型模式**:單例模式,抽象工廠模式,建造者模式,工廠模式與原型模式。
**結構型模式**:適配器模式,橋接模式,裝飾者模式,組合模式,外觀模式,享元模式以及代理模式。
**行為型模式**:模板方法模式,命令模式,迭代器模式,觀察者模式,中介者模式,備忘錄模式,解釋器模式,狀態模式,策略模式,職責鏈模式和訪問者模式。
## 23種設計模式
以下概述主要來源于網絡資料,定義方面的的東西不需要過多記憶,但需要了解,才能更好的理解為什么要使用它。雖然說是來源于網絡,但都是手工碼字,這樣會讓記憶更加深刻。
### 抽象工廠模式(Abstract Factory)
客戶類與工廠類分開,當客戶需要某種產品時向對應工廠發出請求。缺點是當產品需要修改時,工廠類也需要做相應的修改。
**意圖**
提供一個創建一系列相關或者相互依賴的對象接口,無需指定它們具體的類。
**適用性**
一個系統要獨立于它的產品創建,組合的時候。
一個系統要由多個產品系列中的一個來配置的時候。
強調一系列相關產品對象設計以便進行聯合使用時。
對于一個產品庫,只想顯示接口而不是具體的實現的時候。
### 工廠方法模式(Factory Method)
其核心工廠類不再負責所有的產品撞見,而是將具體工作委托給子類,自身成為一個抽象的工廠角色,僅負責給出工廠類必須實現的接口,而不需要關系具體哪種產品被實例化的細節。
**意圖**
定義一個用于創建對象接口,讓子類來決定實例化哪一個類,將類的實例化延遲到其子類。
**適用性**
當一個類不知道它所必須創建的對象的類的時候。
當一個類希望由其子類來創建對象的時候。
### 建造者模式(Builder)
將對象的內部表象和對象的生產過程分割開來,從而使得一個建造過程具有不同內部表象的產品對象。建造模式使得產品內部表象可以獨立出來變化,客戶不需要知道內部細節,可以強制實行一種分步建造過程。
**意圖**
將一個復雜的對象的構建與它的表現分離,使同樣的構建形式可以得到不同的表示。
**適用性**
將復雜對象的算法需要獨立于對象的組成部分以及裝配方式的時候。
構造過程允許構造不同的對象表示。
### 適配器模式(Adapter)
將一個類的接口變為客戶端所希望的接口類型,從而使原先因接口不匹配而無法工作的兩個類可以一起工作。
**意圖**
將某個接口改裝變為所需要類型的接口,也可以是原本不兼容的接口適配成兼容。
**適用性**
希望使用一個已經存在的類,但是與你所需要的接口有些不吻合時。
希望創建一個可以復用的類,可以與其他已存在或者未存在的類進行協同工作。
### 橋接模式(Bridge)
將抽象畫和實例化解耦,使得兩者可以獨立變化。即降低耦合度。也就是說將抽象化和實例化之間的關系使用組合/聚合的關系而非繼承關系,兩者可以獨立的變化。
**意圖**
將抽象部分與它的實現部分分離,使它們可以獨立的變化。
**適用性**
在對于抽象部分和實現部分不希望使用固定的關系。
類的抽象和類的實現都應該都應該可以可以通過生成子類的方式來加以擴充。
對一個抽象的實現部分的修改應對客戶不產生影響。
希望在多個對象之間共享(比如使用引用計數),但是客戶不知道該點。
### 職責鏈模式(Chain of Responsibility)
在職責鏈模式中,很多對象由每一個對象對其下家的引用而連接起來的一條鏈。請求在這個鏈上進行傳遞直到鏈上的某一個對象決定處理該請求。對于鏈上的每一個對象成為處理者,處理者有兩個選擇:承擔處理責任揮著將請求傳遞給下家,請求可以不被任何對象處理。
**意圖**
使多個對象都有機會處理請求,從而避免請求發送者和接受者之間的耦合關系。將這些對象連成一條鏈,并且沿著該鏈傳輸,直到有對象對他進行處理。
**適用性**
有對個對象可以處理一個請求,具體是哪個對象處理會在運行時自動確定。
在不明確接受者情況下,向多個對象提交一個請求。
可以動態的指定那個對象集。
### 命令模式(Command)
命令模式將一個請求或者操作封裝到一個對象中。命令模式將發出命令和執行命令的責任分割開,委派給不同的對象。命令模式也允許請求方個接受方相互獨立,使得請求方不需要知道接收方的接口等。
**意圖**
將一個請求封裝為一個對象,從而可以使你應不同的請求對客戶進行參數化。對于一些排隊的請求可以進行取消操作。
**適用性**
抽象出待執行的動作以參數化某對象可以使用回調表達這種參數化機制。
在不同的時刻指定,排列和執行請求。一個 command 對象可以有一個與初始請求無關的生存期。
支持對于取消,修改操作。
用構建在原語上的高層操作構造一個系統,一個事務封裝了對數據的一組變動,Command模式提供了對事務進行建模的方法,有一個公共的接口,使得可以使用同一種方式來調用所有的事務。也易于添加新事務以擴展系統。
### 組合模式(Composite)
組合模式間對象組織到樹結構中,可以用來描述整體和部分的關系。組合模式就是一個處理對象的樹結構的模式。
**意圖**
將對象組合成樹形結構以表示“部分 - 整體”的層次關系,使用戶對于單個對象和組合對象使用具有一致性。
**適用性**
對于對象希望表現出 部分 - 整體 的層次結構。
希望統一使用組合結構中的所有對象。
### 裝飾者模式(Decorator)
裝飾者模式以對客戶端透明的方式來擴展對象功能,是繼承關系的一個替代方案,提供比繼承更多的靈活性。動態給對象添加功能,這些功能也能動態撤銷。常用于對增加一些基本功能的排列組合而產生的非常大量的功能。
**意圖**
動態的給一個對象添加一些額外的職責。就增加功能來說,裝飾者模式比生成子類更為靈活。
**適用性**
在不影響其他的對象情況下,以動態,透明的方式給單個兌現添加職責。
當無法使用類似生成子類的方式進行類的拓展的時候。如有大量的獨立應用,為支持各種組合那么將出現數量級爆炸的情況,或者類定義被隱藏等不能用于生成子類。
### 外觀模式(Facade 門面模式)
外部與一個子系統的通信必須通過一個統一的門面對象進行。門面模式提供一個更高級的接口使得子系統更容易使用。每一個子系統只有一個門面模式,此門面模式只有一個實例,即單例模式。整個系統中可以有多種門面類。
**意圖**
為子類系統中的一組接口提供一致的界面,外觀模式定義一個高級接口以便子類更容易的調用。
**適用性**
當需要為一個非常復雜的子類系統提供一個簡單的接口的時候。
外觀模式提供一個簡單的缺省視圖,這一視圖對大多數用戶來說已經OK,而對高級用戶可以繞過外觀層進行所需要的處理。
### 享元模式(Flyweight)
享元模式以共享的方式高效的支持大量細粒度對象。共享的關鍵是區分內蘊狀態和外蘊狀態。內蘊狀態存儲在享元內部不會隨環境的改變而有所不同。外蘊狀態就是隨環境的改變而變化的。兩者相互獨立互不影響。將可以共享的狀態和非共享的狀態從常規類里面區分出來。客戶不可以直接創建共享對象,應當使用一個工廠對象負責創建共享的對象。享元模式可以大幅度的降低內存中對象的數量。
**意圖**
運用共享技術有效地支持大量細粒度的對象。
**適用性**
一個程序中使用了大量的對象。
由于對象數量造成了大量存儲開銷。
大多對象的狀態可以變為外部的狀態
可以使用較少的共享對象來進行處理。
### 解析器模式(Interpreter)
給定一個語言后,解析器模式可以定義出其文法的表示,并提供一個解析器。客戶端可以使用這個解析器來解析該語言中的語句。解析器模式將描述怎樣再有了一個簡單的文法后使用模式設計解析這些語句。該語言是指任何解析器對象能夠解釋的任何組合。在解析器模式中需要定義一個代表文法的命令類的等級結構,每一個命令都有一個對應的解釋。
**意圖**
給定一種語言,定義文法表示,并且在定義一個解析器來轉化該語言。
**適用性**
簡化文法所需要的邏輯處理,文法簡單。
### 迭代器模式(Iterator)
迭代器模式可以順序訪問一個聚集中的元素而不必暴露內部表象。多個對象聚集在一起形成的整體稱之為聚集,聚集對象則是包含一組對象的容器。迭代模式將迭代邏輯封裝到一個獨立的對象中,與本身的聚集對象分離開來。迭代模式簡化了聚集的邏輯思想,將行為獨立分割開來方便調整修改替換。所以迭代算法可以獨立于聚集對象進行變化。
**意圖**
提供一個方法順序訪問一個聚合對象中的各個元素而又不暴露該對象的內部表示。
**適用性**
訪問聚合對象,而不希望內部暴露。
支持對于聚合對象的多種遍歷。
為遍歷各種對象提供統一的接口。
### 中介者模式(Mediator)
中介者模式包裝了一系列對象相互作用的方式,使得這些對象不必相互有明顯的聯系。使耦合變得松散。當某些對象發生改變的時候也不會影響其他的對象之間的作用,保證各個對象之間的作用相互獨立,這邊并不是對象與對象之間,而是作用與作用之間的聯系變得獨立開。中介者模式將多對多的相互作用轉化為一對多的相互作用,將對象的行為和協作抽象畫,把對象的一些小行為與其他對象的相互作用分開處理。
**意圖**
使用中介者來封裝一系列的對象之間的交互,不顯示的表示各個對象的相互引用關系,降低對象之間的耦合度。
**適用性**
定義良好的一組對象需要很復雜的通信方式。從而產生的相互依賴關系但以理解。
一個對象直接對其他很多對象進行通信導致了難以復用該對象。
需要定制一個分布在各個類中的行為又不想生成太多子類。
### 備忘錄模式(Memento)
備忘錄對象是一個用來存儲另外一個對象內部狀態的快照對象,在意在不破壞對象封裝的前提下將一個對象的狀態捕捉到,存儲在外部以便可以隨時觀察記錄,以便將來可以還原到某一個狀態。
**意圖**
在不破壞封裝性的前提下捕獲一個對象的內部狀態并將該狀態保存在對象之外來標記。
**適用性**
需要注意必須保持對象的某一時刻狀態并且不對對象造成封裝性的破壞,不制造多余的暴露接口。
### 觀察者模式(Observer)
觀察者模式定義一種一對多的狀態,讓多個觀察者同時監聽某一個對象。這個對象主題發生變化的時候會告知所有的觀察者對象,使它們自動更新自己。
**意圖**
定義對象間的一種一對多的依賴關系,當一個對象發生改變的時候,所有依賴于該對象的其他對象都將得到通知,并且被自動更新。
**適用性**
當抽象模型具有兩個方面,其中一個方面依賴于另一個方面,將這兩者分開封裝在獨立的對象中使得他們可以獨立改變以及復用。
當一個對象在改變的時候需要同時改變其他對象,并且這個對象集合有可能會改變。并且不能假定這些對象來增加耦合度。
### 原型模式(Prototype)
通過給出一個原型對象來指明所要創建的對象類型,復用這個原型對象來創建出個更多的同類型對象。原型模式允許動態的增加或者減少產品類,可以不需要任何的等級結構,原型模式適用于任何結構。
**意圖**
用原型實例來指定對象創建的種類,并且通過拷貝這些原型來創建新的對象。
**適用性**
需要實例化的類在運行時候指定。(對于前端的JSer來說,這是最熟悉不過的了)
### 代理模式(proxy)
代理模式給某一個對象提供一個代理對象,并由代理對象控制對象源對象的引用。在某些情況下客戶不想活著不能夠直接引用一個人對象,代理對象在客戶和目標對象中起到中介者的作用,代理對象可以僅僅只有一個被代理的接口,這時候代理對象不能創建被代理的對象,被代理的對象必須由系統的其他角色代為創建和傳入。
**意圖**
為其他對象提供一種代理來來控制對于某個特定對象的訪問或者處理。
**適用性**
在需要使用比較愛通用和復雜的對象指針來代替簡單指針的時候。
### 單例模式(Singleton)
單例模式確保每一個類只有一個實例,而且自行的實例化并且想整個系統提供該實例的接口。單例模式只有在真正需要單一模式的時候使用。
**結構**
保證一個類只有一個實例,并提供一個訪問它的全局訪問點。
**適用性**
當類只能有一個實例,客戶端通過規范的訪問點來進行訪問。
### 狀態模式(state)
狀態模式允許一個對象在其內部狀態改變的時候改變行為。使得看上去和改變了類是一樣的。狀態模式將所研究的對象的行為包裝在不同的對象里,每一個狀態都屬于一個抽象狀態類的一個子類。狀態模式需要對每一個系統可能取得的狀態創建一個狀態類的子類。當系統的狀態發生變化的時候,系統便改變所選的子類。
**意圖**
允許一個對象在其內部狀態改變的時候改變行為。
**適用性**
一個對象的行為取決于它的狀態,并且必須在運行時刻根據狀態來改變行為。
### 策略模式(Strategy)
策略模式針對一組算法,將每一個算法封裝到具有共同接口的獨立類中,從而使得它們可以相互替換。策略模式使得算法可以在不影響客戶端的情況下發生變化。將行為與環境分開。環境類負責維持和查詢行為類,各個算法在具體的策略類中提供。所以算法的增減不會影響環境和客戶端。
**意圖**
定義一系列算法進行單獨封裝,并且是它們可以相互替換,使算法獨立于客戶變化而變化。
**適用性**
許多相關的類,僅僅是行為上有所差別,策略模式可以實現在多個行為中選取一個來配置一個類。
### 模板方法模式(Template Method)
模板方法模式準備一個抽象類,將部分邏輯以及具體方法以構造子類的方式實現,然后聲明一些抽象方法來事子類實現剩余的邏輯。不同的子類可以以不同的方式來實現這些抽象方法,從而對剩余邏輯的實現。先定制一個頂級的邏輯框架,而將邏輯的細節劉誒具體的子類去實現。
**意圖**
定義一個算法骨架,將一些步驟延遲到子類中,使子類可以不改變一個算法結構卻可以重新定義算法的步驟。
**適用性**
一次性實現算法的不變部分,將可變部分留在子類中實現。
一個類定義多種行為,并且這些行為在這個類中的操作是以多個條件語句的形式出現。
### 訪問者模式(Visitor)
訪問者模式的目的是封裝一些施加于某種數據結構元素之上的操作。一旦操作需要做修改,接受設個操作的數據結構可以保持不變。適用于數據結構相對未定的系統,將數據結構和作用于結構上的操作耦合解脫開使得操作可以相對自由的演化。訪問者模式使得增加新的操作變得更為容易。訪問者模式將有關的行為集中到一個訪問者對象中,而不是分散在一個個環節節點中。當使用訪問者模式的時候要將盡可能多的對象瀏覽邏輯放在訪問者類中,而不是子類中。
**意圖**
表示一個作用于某個對象結構中的各元素的操作,使你可以在不改變各個元素的類的情況下定義作用于這些元素的新的操作。
**適用性**
一個對象結構中包含多個類對象,具有不同的接口,而你希望對這些對象實施一些依賴于具體某個類的操作。
需要對一個對象結構中的對象進行很多不同的并且不想關的操作,這些操作需要避免污染對象。訪問者模式可以將相關的操作集中放入一個類中,被對象結構所共享,從而對象結構中的每個子對象都可以被共享到。
# 參考資料
[Hi~穎峰!的博客](http://blog.chinaunix.net/uid-26672038-id-4067551.html)