23種設計模式彙總:html
簡單工廠模式,策略模式、裝飾模式、代理模式、工廠方法模式、原型模式、模板方法模式、外觀模式、建造者模式、觀察者模式、抽象工廠模式、狀態模式、適配器模式、備忘錄模式、組合模式、迭代器模式、單例模式、橋接模式、命令模式、職責鏈模式、中介者模式、享元模式、解釋器模式、訪問者模式。按照類型分爲: java
一、建立型模式:抽象工廠、建造者模式、工廠方法、原型模式、單例模式;程序員
建立型模式抽象了實例化的過程。建立性模式隱藏了這些類的實例是如何被建立和放在一塊兒,整個系統關於這些對象所知道的是由抽象類所定義的接口。這樣,建立性模式在建立了什麼、誰建立它、她是怎麼被建立的、以及什麼時候建立方面提供了靈活性。建立相應數目的原型並克隆她們一般比每次用適合的狀態手工實例化該類更方便。算法
二、結構型模式:適配器模式、橋接模式、組合模式、裝飾者模式、外觀模式、享元模式、代理模式;數據庫
三、行爲型模式:觀察者模式、模板方法、命令模式、狀態模式、職責鏈模式、解釋器模式、中介者模式、訪問者模式、策略模式、備忘錄模式、迭代器模式。編程
其餘: MVC模式:集觀察者、組合、策略爲一體,是多種模式的綜合應用,算是一種架構模式。設計模式
原則:LSP 里氏替換原則安全
場景:建立不一樣的產品對象,客戶端應使用不一樣的具體工廠。數據結構
優勢:多線程
a) 改變具體工廠便可使用不一樣的產品配置,使改變一個應用的具體工廠變得很容易。
b) 讓具體的建立實例過程與客戶端分離,客戶端經過抽象接口操做實例,產品的具體類名也被具體工廠的實現分離。
缺點:若是要新增方法,改動極大。
應用:
a) jdk中鏈接數據庫的代碼是典型的抽象工廠模式,每一種數據庫只需提供一個統一的接口:Driver(工廠類),並實現其中的方法便可。無論是jdbc仍是odbc都可以經過擴展產品線來達到鏈接自身數據庫的方法。
b) java.util.Collection 接口中定義了一個抽象的 iterator() 方法,該方法就是一個工廠方法。對於 iterator() 方法來講 Collection 就是一個抽象工廠。
原則:依賴倒轉原則
場景:若是須要將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。建造者模式是當建立複雜對象的算法應該獨立於該對象的組成部分以及它們的裝配方式時適用的模式。
優勢:使得建造代碼與表示代碼分離。
缺點:一、增長代碼量;二、Builder只是一個替代構造器的選擇,不能直接用於下降非構造函數方法的參數數量。
應用:StringBuilder和StringBuffer的append()方法
原則:開放封閉原則
場景:不改變工廠和產品體系,只是要擴展產品(變化)。
優勢:是簡單工廠模式的進一步抽象和推廣,既保持了簡單工廠模式的優勢(工廠類中包含了必要的邏輯判斷,根據客戶端的選擇條件動態實例化相關的類。對於客戶端來講,去除了與具體產品的依賴),並且克服了簡單工廠的缺點(違背了開放封閉原則)。
缺點:每增長一個產品,就須要增長一個產品工廠的類,增長了額外的開發。(用反射能夠解決)。
應用:
1. Collection中的iterator方法; 2. java.lang.Proxy#newProxyInstance() 3. java.lang.Object#toString() 4. java.lang.Class#newInstance() 5. java.lang.reflect.Array#newInstance() 6. java.lang.reflect.Constructor#newInstance() 7. java.lang.Boolean#valueOf(String) 8. java.lang.Class#forName()
原則:
場景:在初始化信息不發生變化的狀況,用克隆進行拷貝。
優勢:隱藏了對象建立的細節,大大提高了性能。不用從新初始化對象,而是動態的得到對象運行時的狀態。
缺點:深複製 or 淺複製 。
應用:JDK中的Date類。
原則:封裝
場景:一般,咱們可讓一個全局變量使得一個對象被訪問,但它不能防止你實例化多個對象,一個最好的辦法就是,讓類自身負責保存它的惟一實例。這個類能夠保證沒有其餘實例能夠被建立,並且它能夠提供一個訪問該實例的方法。
優勢:對惟一實例的受控訪問。
缺點:餓漢式/懶漢式 多線程同時訪問時可能形成多個實例。
應用:java.lang.Runtime; GUI中也有一些(java.awt.Toolkit#getDefaultToolkit() java.awt.Desktop#getDesktop())
在GoF的設計模式中,適配器有兩種類型,類適配器模式和對象適配器模式。
a) 類適配器模式:經過多重繼承對一個接口與另外一個接口進行匹配,而C#,Java等語言都不支持多重繼承,也就是一個類只有一個父類。
b) Java通常都指的是 對象適配器模式
場景:適配器是爲了複用一些現有的類。系統的數據和行爲都正確,可是接口不符,這時採用適配器模式,使原有對象和新接口匹配。
優勢:可以複用現存的類,客戶端統一調用同一接口,更簡單、直接、緊湊。
缺點:適配器模式有點兒「亡羊補牢」的感受,設計階段要避免使用。
應用:在Java jdk中,適配器模式使用場景不少,如集合包中Java.util.Arrays#asList()、IO包中java.io.InputStreamReader(InputStream)、java.io.OutputStreamWriter(OutputStream) 等
原則:合成/聚合複用原則
場景:實現系統可能有多角度分類,每一種分類都有可能變化,那麼就把這種多角度分離出來讓它們獨立變化,減小它們之間的耦合。
優勢:減小各部分的耦合。 分離抽象和實現部分,更好的擴展性,可動態地切換實現、可減小子類的個數。
缺點:一、橋接模式的引入會增長系統的理解與設計難度,因爲聚合關聯關係創建在抽象層,要求開發者針對抽象進行設計與編程。 二、橋接模式要求正確識別出系統中兩個獨立變化的維度,所以其使用範圍具備必定的侷限性
應用:Collections類中的sort()方法;AWT;JDBC數據庫訪問接口API;
場景:需求中體現部分與總體層次結構時,以及但願用戶能夠忽略組合對象與單個對象的不一樣,統一使用組合結構中的全部對象時,就應該考慮使用組合模式了。
優勢:組合模式讓客戶能夠一致的使用組合結構和單個對象。
缺點:使設計變得更加抽象,對象的業務規則若是很複雜,則實現組合模式具備很大挑戰性,並且不是全部的方法都與葉子對象子類都有關聯。
應用:JDK中AWT包和Swing包的設計是基於組合模式,在這些界面包中爲用戶提供了大量的容器構件(如Container)和成員構件(如Checkbox、Button和TextComponent等),他們都是繼承、關聯自抽象組件類Component。
場景:裝飾模式是爲了已有功能動態地添加更多功能的一種方式,當系統須要新功能的時候,是向舊類中添加新的代碼,這些新的代碼一般裝飾了原有類的核心職責或主要行爲。裝飾着模式把每一個要裝飾的功能放在單獨的類中,並讓這個類包裝它所要裝飾的對象,當須要執行特殊行爲時,客戶代碼就能夠在運行時根據須要有選擇的、按順序地使用裝飾功能包裝對象。
優勢:把類中的裝飾功能從類中搬移出去,簡化原有的類。有效的把類的核心職責和裝飾功能區分開,去除相關類中重複的裝飾邏輯。
缺點:利用裝飾器模式,經常形成設計中有大量的小類,數量實在太多,可能會形成使用此API程序員的困擾。
應用:Java I/O使用裝飾模式設計,JDK中還有不少類是使用裝飾模式設計的,如:Reader類、Writer類、OutputStream類等。
原則:完美的體現了依賴倒轉原則和迪米特法則。
場景:
a) 設計階段:需有意識的將不一樣的兩個層分離。
b) 開發階段:增長外觀façade提供一個簡單的接口,應對子類的重演和演化。
c) 維護期間:使用façade類,爲遺留代碼提供清晰簡單的接口,讓新系統與façade交互,façade與遺留代碼交互全部複雜的工做。
優勢:一、客戶對子系統的使用變得簡單了,減小了與子系統的關聯對象,實現了子系統與客戶之間的鬆耦合關係。 二、只是提供了一個訪問子系統的統一入口,並不影響用戶直接使用子系統類 三、下降了大型軟件系統中的編譯依賴性,並簡化了系統在不一樣平臺之間的移植過程。
缺點:一、不能很好地限制客戶使用子系統類,若是對客戶訪問子系統類作太多的限制則減小了可變性和靈活性 二、在不引入抽象外觀類的狀況下,增長新的子系統可能須要修改外觀類或客戶端的源代碼,違背了「開閉原則」。
場景:若是一個應用程序使用了大量的對象,而大量的這些對象形成了很大存儲開銷時就應該考慮使用享元模式;還有就是對象大多數狀態均可爲外部狀態,若是刪除對象的外部狀態,那麼能夠用相對較少的共享對象取代不少組對象,此時能夠考慮使用享元模式。
優勢:享元模式能夠避免大量很是類似類的開銷。程序中,大量細粒度的類實例來表示數據,若是它們除了幾個參數外基本相同,那麼把它們轉移到類實例的外面,在方法調用時將它們傳遞進來,就能夠經過共享大幅度減小單個實例的數目。
缺點:一、因爲享元模式須要區分外部狀態和內部狀態,使得應用程序在某種程度上來講更加複雜化了。二、爲了使對象能夠共享,享元模式須要將享元對象的狀態外部化,而讀取外部狀態使得運行時間變長。
應用:String 類。
原則:代理模式就是在訪問對象時引入必定程度的間接性。(迪米特法則?)
場景:
a) 遠程代理:爲一個對象在不一樣的地址空間提供局部表明,這樣能夠隱藏一個對象存在於不一樣地址空間的事實。【WebService,客戶端能夠調用代理解決遠程訪問問題】
b) 虛擬代理:根據須要建立開銷很大的對象,經過它來存放實例化須要很長時間地真實對象。【好比Html網頁的圖片,代理存儲的是真實圖片的路徑和尺寸】
c) 安全代理:用來控制真實對象的訪問權限。
d) 智能指引:當調用真實的對象時,代理處理另外一些事。【如計算機真實對象的引用次數,代理在訪問一個對象的時候回附加一些內務處理,檢查對象是否被鎖定、是否該釋放、是否該裝入內存等等】
優勢:1)代理模式能將代理對象與真正被調用的對象分離,在必定程度上下降了系統的耦合度。
2)代理模式在客戶端和目標對象之間起到一箇中介做用,這樣能夠起到保護目標對象的做用。代理對象也能夠對目標對象調用以前進行其餘操做。
缺點:1)在客戶端和目標對象增長一個代理對象,會形成請求處理速度變慢。
2)增長了系統的複雜度。
應用:java.lang.reflect 包中的Proxy類和InvocationHandler 接口提供了生成動態代理類的能力。
場景:將一個系統分割成一系列互相協做的類,有一個缺點:須要維護相關對象間的一致性。緊密的耦合會給維護和擴展帶來不便。觀察者模式就是爲了解耦而誕生的,讓本來一個對象依賴另外一個對象的關係,變成了兩方都依賴於抽象,而再也不依賴於具體,從而使得各自的變化都不會影響另外一邊的變化。
優勢:解耦。
缺點:若是在被觀察者之間有循環依賴的話,被觀察者會觸發它們之間進行循環調用,致使系統崩潰。在使用觀察者模式是要特別注意這一點。
應用:java.util.Observer , java類庫實現觀察着(Observer)模式的類和接口。
原則:代碼複用平臺。
場景:遇到由一系列步驟構成的過程須要執行,這個過程從高層次上看是相同的,可是有些步驟的實現可能不一樣,這個時候就須要考慮用模板方法模式了。
優勢:模板方法模式是經過把不變行爲搬移到超類,去除子類中重複代碼來實現它的優點,提供了一個代碼複用平臺,幫助子類擺脫重複的不變行爲的糾纏。
缺點:若是父類中可變的基本方法太多,將會致使類的個數增長,系統更加龐大。
應用:AbstractClass抽象類裏面的TemplateMethod()就是模板方法。
原則:敏捷開發原則
場景:對請求排隊或記錄請求日誌,以及支持可撤銷的操做等行爲。
優勢:
a) 命令模式把請求一個操做的對象與知道怎麼執行一個操做的對象分割開。
b) 它能較容易的設計一個命令隊列。
c) 在須要的狀況下,能夠較容易的將命令記入日誌。
d) 容許接收請求的一方決定是否要否決請求。
e) 能夠容易的實現對請求的撤銷和重作。
f) 因爲加進新的具體命令類不影響其餘類,所以增長新的具體命令類很容易。
缺點:會增長系統的複雜性,這裏的複雜性應該主要指的是類的數量。
應用:
1. java.util.Timer類中scheduleXXX()方法
2. java Concurrency Executor execute()方法
3. java.lang.reflect.Methodinvoke()方法
原則:單一職責原則
場景:當一個對象的行爲取決於它的狀態,而且它必須在運行時刻根據狀態改變它的行爲時,能夠考慮使用狀態模式了。
優勢:狀態模式主要解決的是當控制一個對象狀態轉換的條件表達式過於複雜的狀況。把狀態的判斷邏輯轉移到表示不一樣狀態的一系列類當中,能夠把複雜的判斷邏輯簡化。【消除龐大的條件分支語句】。
缺點:違背開放-封閉原則
應用:
1. java.util.Iterator
2. javax.faces.lifecycle.LifeCycle#execute()
場景:當客戶提交一個請求時,請求是沿鏈傳遞直至有一個對象負責處理它。
優勢:使得接收者和發送者都沒有對方的明確信息,且鏈中對象本身也不知道鏈結構,結果是職責鏈能夠簡化對象的相互鏈接,它們只須要保持一個指向其後繼者的引用,而不需 要保持它全部的候選接收者的引用。開發者能夠隨時的增長或者修改處理一個請求的結構,加強了給對象指派職責的靈活性。
缺點:一個請求極有可能到了鏈的末端都得不處處理,或者由於沒有正確配置而得不處處理。
原則:依賴倒轉原則
場景:若是一種特定類型問題發生的頻率足夠高,那麼可能就值得將該問題的各個實例表述爲一個簡單語句中的句子。這樣就能夠構建一個解釋器,該解釋器經過解釋這些句子來解決該問題。當一個語言須要執行,而且你可將該語言中的句子表示爲一個抽象語法樹時,能夠用解釋器模式。
優勢:解釋器很容易改變和擴展文法,由於該模式使用類來表示文法規則,可使用繼承來改變或擴展文法,也比較容易實現文法。由於定義抽象語法樹中各個節點的類的實現大致相似,這些類都易於直接編寫。
缺點:解釋器模式爲文法中的每一條規則至少定義了一個類,所以包含許多規則的文法可能難以管理和維護,建議當文法很是複雜時,使用其餘技術(語法分析程序、編譯器生成器)。
應用:
1. java.util.Pattern
2. java.text.Normalizer
3. java.text.Format
4. javax.el.ELResolver
場景:通常應用於一組對象以定義良好可是複雜的方式進行通訊的場合,以及想定製一個分佈在多個類的行爲,而又不想生成太多子類的場合。【例如,Form窗體,或者aspx頁面】。
優勢:
a) 抽象中介者類(Mediator)減小了抽象同事類(colleague)之間的耦合,是的能夠獨立的改變和複用各個類。
b) 因爲把對象如何協做進行了抽象,將中介做爲一個獨立的概念並將其封裝在一個對象中,這樣關注的對象就從對象各自自己的行爲轉移到它們之間的交互上來,也就是站在一個更宏觀的角度去看待系統。
缺點:控制集中化致使了中介者的複雜化。
應用:
1. java.util.Timer
2. java.util.concurrent.Executor#execute()
3. java.util.concurrent.ExecutorService#submit()
4. java.lang.reflect.Method#invoke()
場景:訪問者模式適合有穩定的數據結構、又有易於變化的算法】訪問者模式適用於數據結構相對穩定的系統,它把數據結構和做用於結構上的操做之間的耦合解脫開,是的操做集合能夠相對自由的演化。訪問者模式的目的是要把處理從數據結構中分離出來。
優勢:增長新的操做很容易。新的操做就是新的訪問者。
缺點:很難增長新的數據結構。
應用:
1. javax.lang.model.element.AnnotationValue和AnnotationValueVisitor
2. javax.lang.model.element.Element和ElementVisitor
3. javax.lang.model.type.TypeMirror和TypeVisitor
場景:策略模式不只能夠用來封裝算法,幾乎能夠封裝縫合類型的規則,不一樣的業務邏輯均可以考慮用策略模式處理變化。
優勢:策略模式的策略類爲上下文定義了一系列可供重用的算法或行爲,繼承有助於析取出這些算法中的公共功能。另外,策略模式簡化了單元測試,由於每個算法都有本身的類,能夠經過本身的接口單獨測試。當不一樣的行爲堆砌在一個類中,很難避免使用switch語句。可是將這些行爲封裝在一個一個獨立的策略類中,能夠在使用這些行爲的類中消除條件語句
缺點:基本的策略模式,選擇權在客戶端,具體實現轉給策略模式的上下文對象。這並很差。使用策略模式和工廠類結合,能夠減輕客戶端的職責。可是仍是不夠完美,使用反射才能真正快樂。
應用:
1. java.util.Comparator#compare()
2. javax.servlet.http.HttpServlet
3. javax.servlet.Filter#doFilter()
場景:Memento封裝要保存的細節,適合功能負責但須要維護或記錄屬性歷史的類,或者是須要保存的屬性只是衆多屬性中的一個小部分。
優勢:使用備忘錄模式能夠把複雜的發起人內部信息對其餘的對象屏蔽起來,從而能夠恰當地保持封裝的邊界。
缺點:若是發起人角色的狀態須要完整地存儲到備忘錄對象中,那麼在資源消耗上面備忘錄對象會很昂貴。
應用:
1. java.util.Date
2. java.io.Serializable
場景:當須要對彙集有多種方式遍歷時,能夠考慮使用迭代器。
優勢:迭代器模式就是分離了集合對象的遍歷行爲,抽象出一個迭代器來負責,這樣既能夠作到不暴露集合的內部結構,又可讓外部代碼透明的訪問集合內部的數據。
缺點:因爲迭代器模式將存儲數據和遍歷數據的職責分離,增長新的聚合類須要對應增長新的迭代器類,類的個數成對增長,這在必定程度上增長了系統的複雜性。
應用:collection容器使用了迭代器模式
設計模式在JDK的應用:http://www.javashuo.com/article/p-adaaslxp-ed.html