1. 程式人生 > >二十三種設計模式_概述

二十三種設計模式_概述

概述及詳解:https://blog.csdn.net/qq_25827845/article/details/52932234

 

 

一、Singleton,單例模式:保證一個類只有一個例項,並提供一個訪問它的全域性訪問點
二、Abstract Factory,抽象工廠:提供一個建立一系列相關或相互依賴物件的介面,而無須指定它們的具體類。
三、Factory Method,工廠方法:定義一個用於建立物件的介面,讓子類決定例項化哪一個類,Factory Method使一個類的例項化延遲到了子類。(定義一個用於建立物件的介面,介面返回需要建立的物件的父類,讓子類實現這個介面並在接口裡面建立對應的物件)

四、Builder,建造模式:將一個複雜物件的構建與他的表示相分離,使得同樣的構建過程可以建立不同的表示。
五、Prototype,原型模式:用原型例項指定建立物件的種類,並且通過拷貝這些原型來建立新的物件。
行為型有:
六、Iterator,迭代器模式:提供一個方法順序訪問一個聚合物件的各個元素,而又不需要暴露該物件的內部表示。
七、Observer,觀察者模式:定義物件間一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知自動更新。
八、Template Method,模板方法:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中,TemplateMethod使得子類可以不改變一個演算法的結構即可以重定義該演算法得某些特定步驟。
九、Command,命令模式:將一個請求封裝為一個物件,從而使你可以用不同的請求對客戶進行引數化,對請求排隊和記錄請求日誌,以及支援可撤銷的操作。
十、State,狀態模式:允許物件在其內部狀態改變時改變他的行為。物件看起來似乎改變了他的類。
十一、Strategy,策略模式:定義一系列的演算法,把他們一個個封裝起來,並使他們可以互相替換,本模式使得演算法可以獨立於使用它們的客戶。
十二、China of Responsibility,職責鏈模式:使多個物件都有機會處理請求,從而避免請求的送發者和接收者之間的耦合關係
十三、Mediator,中介者模式:用一箇中介物件封裝一些列的物件互動。
十四、Visitor,訪問者模式:表示一個作用於某物件結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用於這個元素的新操作。
十五、Interpreter,直譯器模式:給定一個語言,定義他的文法的一個表示,並定義一個直譯器,這個直譯器使用該表示來解釋語言中的句子。
十六、Memento,備忘錄模式:在不破壞物件的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。
結構型有:
十七、Composite,組合模式:將物件組合成樹形結構以表示部分整體的關係,Composite使得使用者對單個物件和組合物件的使用具有一致性。
十八、Facade,外觀模式:為子系統中的一組介面提供一致的介面,fa?ade提供了一高層介面,這個介面使得子系統更容易使用。
十九、Proxy,代理模式:為其他物件提供一種代理以控制對這個物件的訪問
二十、Adapter,介面卡模式:將一類的介面轉換成客戶希望的另外一個介面,Adapter模式使得原本由於介面不相容而不能一起工作那些類可以一起工作。
二十一、Decrator,裝飾模式:動態地給一個物件增加一些額外的職責,就增加的功能來說,Decorator模式相比生成子類更加靈活。
二十二、Bridge,橋模式:將抽象部分與它的實現部分相分離,使他們可以獨立的變化。
二十三、Flyweight,享元模式

 

一句話理解23種設計模式

設計模式的幾大原則

Ø  開放-封閉原則:對擴充套件開放,對修改封閉,可以用新的類來解決問題

Ø  單一職責原則:設計目的單一的類。也就是降低程式的耦和程度

Ø  李氏替換原則:用子類去替代父類

Ø  依賴倒置原則:依賴於抽象,而不依賴於具體的實現;針對介面程式設計,不針對實現程式設計

Ø  介面隔離原則:使用多個介面總比使用單個介面要好

Ø  組合重用原則:儘量使用組合,而不是使用繼承來達到重用的目的,因為繼承是一種緊偶和

Ø  最少知道原則:一個物件應當對其他物件有儘可能少的瞭解,即資訊隱蔽

 

設計模式的分類

設計模式可以分為:建立型模式、結構型模式、行為型模式

建立型模式作用:主要用於建立物件,為類例項化物件提供指南

結構型模式作用:主要用於處理類和物件的組合,對類如何設計以形成更大的結構提供指南

行為型模式作用:主要用於描述類或物件的互動以及職責的互動,對類之間互動以及分配責任提供指南

 

建立型模式:

1. 工廠方法模式(Factory Methord)

定義一個建立物件的介面,有子類決定需要例項化哪一個類。工廠方法使得子類的例項化過程推遲

2. 抽象工廠模式(Abstract Factory)

提供一個介面,可以建立一系列物件,而不用制定它們具體的類

3. 構建器模式(Builder)

將一個複雜類的表示與其構造相分離,使得相同的構建過程能得到不同的表示

4. 原型模式(Prototype)

用原型例項指定建立物件的型別,並通過copy這個原型來建立新的物件

5. 單例模式(Singleton)

保證一個類只有一個例項,並提供一個訪問它的全域性訪問點

 

結構型模式

1. 介面卡模式(Adapter)

將一個類的介面轉換成使用者希望得到的另一種介面。

關鍵字:轉換介面

2. 橋接模式(Bridge)

將類的抽象部分和實現部分分離開來,使它們可以獨立地變化。也就是把一棵樹拆成2棵樹,再把兩棵樹連線起來。也就是繼承與拆分

3. 組合模式(Composite)

將物件組合成樹形結構以表示“整體-部分”的層次結構,使得使用者對單個物件和組合物件的使用具有一致性。

關鍵字:樹形目錄結構

4. 裝飾模式(Decorator)

動態給一個物件新增一些額外的職責。

關鍵字:附加職責

5. 外觀模式(Facade)

定義一個高層介面,為子系統中的一組介面提供一個一致的外觀。

關鍵字:對外統一介面

6. 享元模式(Flyweight)

提供支援大量細粒度物件共享的有效方法。

關鍵字:漢字編碼

7. 代理模式(Proxy)

為其他物件提供一種代理以控制這個物件的訪問。

關鍵字:快捷方式

 

行為型模式

1. 職責鏈模式

通過給多個物件處理請求的機會,減少請求的傳送者與接收者之間的耦合。將接收物件連結起來,在鏈中傳遞請求,直到有一個物件處理這個請求。

關鍵字:傳遞職責,檢索非法關鍵字

2. 命令模式(Command)

將一個請求封裝為一個物件,從而可用不同的請求對客戶進行引數化,將請求排隊或者記錄請求日誌,支援可4撤銷操作。

關鍵字:日誌記錄,可撤銷

3. 直譯器模式(Interpreter)

給定一種語言,定義它的文法表示,並定義一個直譯器,該直譯器用來根據文法表示來解釋語言中的句子。

關鍵字:虛擬機器機制

例如:解釋自定義語言

4. 迭代器模式(Iterator)

提供一種方法來順序訪問一個聚合物件中的各個元素,而不需要暴露該物件的內部表示。關鍵字:資料集

5. 中介者模式(Mediator)

用一箇中介物件來封裝一系列的互動。它使各物件不需要顯式地相互呼叫,從而達到低耦合,還可以獨立地改變物件之間的互動。

也就是將網狀結構該為星形結構

關鍵字:不直接引用

例如:銀行之間業務的對接(銀聯)

6. 備忘錄模式(Memento)

儲存一個物件的某個狀態,以便在適當的時候恢復物件

7. 觀察者模式(Observer)

定義物件之間的一種一對多的依賴關係,當一個物件的狀態發生變化時,所有依賴於它的物件都得到通知並自動更新

關鍵字:聯動

例如:釋出和訂閱

8. 狀態模式(State)

允許一個物件在其內部狀態改變時改變他的行為

關鍵字:狀態變成類

例如:會員卡的狀態(銅-銀-金)

9. 策略模式(Syategy)

定義一系列演算法,把它們一個個封裝起來,並且使它們之間可相互替換,從而讓演算法可以獨立於使用它的使用者而變化。

關鍵字:多方案切換

例如:商場的滿減和 打折

10. 模版方法模式(Templatemethod)

定義一個操作中的演算法骨架,而將一些步驟延遲到子類中。

11. 訪問者模式(Visitor)

一種分離物件資料結構與行為的方法。通過這種分離,可達到一個被訪問者動態新增新的操作而無需做其他的修改的效果。

適用於資料結構相對穩定,演算法易變化的系統。
--------------------- 
作者:飛天絮雪 
來源:CSDN 
原文:https://blog.csdn.net/feitianxuxue/article/details/77740227 
 

 

簡單工廠模式

簡單工廠模式模式分為三種:

普通簡單工廠、多方法簡單工廠、靜態方法簡單工廠。

是對普通工廠方法模式的改進,在普通工廠方法模式中,如果傳遞的字串出錯,則不能正確建立物件,而多個工廠方法模式是提供多個工廠方法,分別建立物件。

1、工廠方法模式(Factory Method)

 

簡單工廠模式有一個問題就是,類的建立依賴工廠類,也就是說,如果想要拓展程式,必須對工廠類進行修改,這違背了閉包原則,所以,從設計角度考慮,有一定的問題,如何解決?就用到工廠方法模式,建立一個工廠介面和建立多個工廠實現類,這樣一旦需要增加新的功能,直接增加新的工廠類就可以了,不需要修改之前的程式碼。

2、抽象工廠模式

工廠方法模式和抽象工廠模式不好分清楚,他們的區別如下:

 

<span style="">工廠方法模式:
一個抽象產品類,可以派生出多個具體產品類。   
一個抽象工廠類,可以派生出多個具體工廠類。   
每個具體工廠類只能建立一個具體產品類的例項。

抽象工廠模式:
多個抽象產品類,每個抽象產品類可以派生出多個具體產品類。   
一個抽象工廠類,可以派生出多個具體工廠類。   
每個具體工廠類可以建立多個具體產品類的例項,也就是建立的是一個產品線下的多個產品。  

3、單例模式(Singleton

單例物件(Singleton)是一種常用的設計模式。在Java應用中,單例物件能保證在一個JVM中,該物件只有一個例項存在。這樣的模式有幾個好處:

1、某些類建立比較頻繁,對於一些大型的物件,這是一筆很大的系統開銷。

2、省去了new操作符,降低了系統記憶體的使用頻率,減輕GC壓力。

3、有些類如交易所的核心交易引擎,控制著交易流程,如果該類可以建立多個的話,系統完全亂了。(比如一個軍隊出現了多個司令員同時指揮,肯定會亂成一團),所以只有使用單例模式,才能保證核心交易伺服器獨立控制整個流程。

 

4、建造者模式(Builder)

 

 

 

5、原型模式(Prototype)

 

原型模式雖然是建立型的模式,但是與工程模式沒有關係,從名字即可看出,該模式的思想就是將一個物件作為原型,對其進行復制、克隆,產生一個和原物件類似的新物件。本小結會通過物件的複製,進行講解。

6、介面卡模式

 介面卡模式將某個類的介面轉換成客戶端期望的另一個介面表示,目的是消除由於介面不匹配所造成的類的相容性問題。主要分為三類:類的介面卡模式、物件的介面卡模式、介面的介面卡模式。

7、裝飾模式(Decorator)

顧名思義,裝飾模式就是給一個物件增加一些新的功能,而且是動態的,要求裝飾物件和被裝飾物件實現同一個介面,裝飾物件持有被裝飾物件的例項,

8、代理模式(Proxy)

其實每個模式名稱就表明了該模式的作用,代理模式就是多一個代理類出來,替原物件進行一些操作,比如我們在租房子的時候回去找中介,為什麼呢?因為你對該地區房屋的資訊掌握的不夠全面,希望找一個更熟悉的人去幫你做,此處的代理就是這個意思。再如我們有的時候打官司,我們需要請律師,因為律師在法律方面有專長,可以替我們進行操作,表達我們的想法。

9、外觀模式(Facade)

外觀模式是為了解決類與類之家的依賴關係的,像spring一樣,可以將類和類之間的關係配置到配置檔案中,而外觀模式就是將他們的關係放在一個Facade類中,降低了類類之間的耦合度,該模式中沒有涉及到介面,

10、橋接模式(Bridge)

橋接模式就是把事物和其具體實現分開,使他們可以各自獨立的變化。橋接的用意是:將抽象化與實現化解耦,使得二者可以獨立變化,像我們常用的JDBC橋DriverManager一樣,JDBC進行連線資料庫的時候,在各個資料庫之間進行切換,基本不需要動太多的程式碼,甚至絲毫不用動,原因就是JDBC提供統一介面,每個資料庫提供各自的實現,用一個叫做資料庫驅動的程式來橋接就行了。

11、組合模式(Composite)

組合模式有時又叫部分-整體模式在處理類似樹形結構的問題時比較方便,

12、享元模式(Flyweight)

享元模式的主要目的是實現物件的共享,即共享池,當系統中物件多的時候可以減少記憶體的開銷,通常與工廠模式一起使用。

FlyWeightFactory負責建立和管理享元單元,當一個客戶端請求時,工廠需要檢查當前物件池中是否有符合條件的物件,如果有,就返回已經存在的物件,如果沒有,則建立一個新物件

13、策略模式(strategy)

策略模式定義了一系列演算法,並將每個演算法封裝起來,使他們可以相互替換,且演算法的變化不會影響到使用演算法的客戶。需要設計一個介面,為一系列實現類提供統一的方法,多個實現類實現該介面,設計一個抽象類(可有可無,屬於輔助類),提供輔助函式

14、模板方法模式(Template Method)

解釋一下模板方法模式,就是指:一個抽象類中,有一個主方法,再定義1...n個方法,可以是抽象的,也可以是實際的方法,定義一個類,繼承該抽象類,重寫抽象方法,通過呼叫抽象類,實現對子類的呼叫

15 觀察者者模式(Observer)

包括這個模式在內的接下來的四個模式,都是類和類之間的關係,不涉及到繼承,學的時候應該 記得歸納,記得本文最開始的那個圖。觀察者模式很好理解,類似於郵件訂閱和RSS訂閱,當我們瀏覽一些部落格或wiki時,經常會看到RSS圖示,就這的意思是,當你訂閱了該文章,如果後續有更新,會及時通知你。其實,簡單來講就一句話:當一個物件變化時,其它依賴該物件的物件都會收到通知,並且隨著變化!物件之間是一種一對多的關係。

16、迭代子模式(Iterator)

顧名思義,迭代器模式就是順序訪問聚集中的物件,一般來說,集合中非常常見,如果對集合類比較熟悉的話,理解本模式會十分輕鬆。這句話包含兩層意思:一是需要遍歷的物件,即聚集物件,二是迭代器物件,用於對聚集物件進行遍歷訪問。

17、責任鏈模式(Chain of Responsibility)

接下來我們將要談談責任鏈模式,有多個物件,每個物件持有對下一個物件的引用,這樣就會形成一條鏈,請求在這條鏈上傳遞,直到某一物件決定處理該請求。但是發出者並不清楚到底最終那個物件會處理該請求,所以,責任鏈模式可以實現,在隱瞞客戶端的情況下,對系統進行動態的調整。

18、命令模式(Command)

命令模式很好理解,舉個例子,司令員下令讓士兵去幹件事情,從整個事情的角度來考慮,司令員的作用是,發出口令,口令經過傳遞,傳到了士兵耳朵裡,士兵去執行。這個過程好在,三者相互解耦,任何一方都不用去依賴其他人,只需要做好自己的事兒就行,司令員要的是結果,不會去關注到底士兵是怎麼實現的

19、備忘錄模式(Memento)

主要目的是儲存一個物件的某個狀態,以便在適當的時候恢復物件,個人覺得叫備份模式更形象些,通俗的講下:假設有原始類A,A中有各種屬性,A可以決定需要備份的屬性,備忘錄類B是用來儲存A的一些內部狀態,類C呢,就是一個用來儲存備忘錄的,且只能儲存,不能修改等操作。

20、狀態模式(State)

核心思想就是:當物件的狀態改變時,同時改變其行為,很好理解!就拿QQ來說,有幾種狀態,線上、隱身、忙碌等,每個狀態對應不同的操作,而且你的好友也能看到你的狀態,所以,狀態模式就兩點:1、可以通過改變狀態來獲得不同的行為。2、你的好友能同時看到你的變化。

21、訪問者模式(Visitor)

 

訪問者模式把資料結構和作用於結構上的操作解耦合,使得操作集合可相對自由地演化。訪問者模式適用於資料結構相對穩定演算法又易變化的系統。因為訪問者模式使得演算法操作增加變得容易。若系統資料結構物件易於變化,經常有新的資料物件增加進來,則不適合使用訪問者模式。訪問者模式的優點是增加操作很容易,因為增加操作意味著增加新的訪問者。訪問者模式將有關行為集中到一個訪問者物件中,其改變不影響系統資料結構。其缺點就是增加新的資料結構很困難。

22、中介者模式(Mediator)

 

中介者模式也是用來降低類類之間的耦合的,因為如果類類之間有依賴關係的話,不利於功能的拓展和維護,因為只要修改一個物件,其它關聯的物件都得進行修改。如果使用中介者模式,只需關心和Mediator類的關係,具體類類之間的關係及排程交給Mediator就行,這有點像spring容器的作用。

23、直譯器模式(Interpreter)

直譯器模式是我們暫時的最後一講,一般主要應用在OOP開發中的編譯器的開發中,所以適用面比較窄。

 

 

 

 

轉載自:https://www.cnblogs.com/tongkey/p/7170826.html

1.單例模式(Singleton Pattern)

定義:Ensure a class has only one instance, and provide a global point of access to it.(確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。)

通用程式碼:(是執行緒安全的)

複製程式碼

public class Singleton {
     private static final Singleton singleton = new Singleton();
//限制產生多個物件
     private Singleton(){
     }
     //通過該方法獲得例項物件
     public static Singleton getSingleton(){
             return singleton;
     }  
     //類中其他方法,儘量是static
     public static void doSomething(){
     }
}

複製程式碼

 

使用場景:

● 要求生成唯一序列號的環境;

● 在整個專案中需要一個共享訪問點或共享資料,例如一個Web頁面上的計數器,可以不用把每次重新整理都記錄到資料庫中,使用單例模式保持計數器的值,並確保是執行緒安全的;

● 建立一個物件需要消耗的資源過多,如要訪問IO和資料庫等資源;

● 需要定義大量的靜態常量和靜態方法(如工具類)的環境,可以採用單例模式(當然,也可以直接宣告為static的方式)。

 

執行緒不安全例項:

  

複製程式碼

public class Singleton {
     private static Singleton singleton = null; 
     //限制產生多個物件
     private Singleton(){
     }  
     //通過該方法獲得例項物件
     public static Singleton getSingleton(){
             if(singleton == null){
                    singleton = new Singleton();
             }
             return singleton;
     }
}

複製程式碼

 

 

 

解決辦法:

在getSingleton方法前加synchronized關鍵字,也可以在getSingleton方法內增加synchronized來實現。最優的辦法是如通用程式碼那樣寫。

2.工廠模式

定義:Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclasses.(定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。)

   

 

Product為抽象產品類負責定義產品的共性,實現對事物最抽象的定義;

Creator為抽象建立類,也就是抽象工廠,具體如何建立產品類是由具體的實現工廠ConcreteCreator完成的。

具體工廠類程式碼:

複製程式碼

public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c){
             Product product=null;
             try {
                    product = (Product)Class.forName(c.getName()).newInstance();
             } catch (Exception e) {
                    //異常處理
             }
             return (T)product;         
     }
}

複製程式碼

 

簡單工廠模式:

一個模組僅需要一個工廠類,沒有必要把它產生出來,使用靜態的方法

多個工廠類:

每個人種(具體的產品類)都對應了一個建立者,每個建立者獨立負責建立對應的產品物件,非常符合單一職責原則

代替單例模式:

單例模式的核心要求就是在記憶體中只有一個物件,通過工廠方法模式也可以只在記憶體中生產一個物件

延遲初始化:

ProductFactory負責產品類物件的建立工作,並且通過prMap變數產生一個快取,對需要再次被重用的物件保留

使用場景:jdbc連線資料庫,硬體訪問,降低物件的產生和銷燬

3.抽象工廠模式(Abstract Factory Pattern)

定義:Provide an interface for creating families of related or dependent objects without specifying their concrete classes.(為建立一組相關或相互依賴的物件提供一個介面,而且無須指定它們的具體類。)

抽象工廠模式通用類圖:

抽象工廠模式通用原始碼類圖:

抽象工廠類程式碼:

public abstract class AbstractCreator {
     //建立A產品家族
     public abstract AbstractProductA createProductA(); 
     //建立B產品家族
     public abstract AbstractProductB createProductB();
}

使用場景:

一個物件族(或是一組沒有任何關係的物件)都有相同的約束。

涉及不同作業系統的時候,都可以考慮使用抽象工廠模式

 

4.模板方法模式(Template Method Pattern)

定義:Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.(定義一個操作中的演算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個演算法的結構即可重定義該演算法的某些特定步驟。)

AbstractClass叫做抽象模板,它的方法分為兩類:

● 基本方法

基本方法也叫做基本操作,是由子類實現的方法,並且在模板方法被呼叫。

● 模板方法

可以有一個或幾個,一般是一個具體方法,也就是一個框架,實現對基本方法的排程,完成固定的邏輯。

注意: 為了防止惡意的操作,一般模板方法都加上final關鍵字,不允許被覆寫。

具體模板:ConcreteClass1和ConcreteClass2屬於具體模板,實現父類所定義的一個或多個抽象方法,也就是父類定義的基本方法在子類中得以實現

使用場景:

● 多個子類有公有的方法,並且邏輯基本相同時。

● 重要、複雜的演算法,可以把核心演算法設計為模板方法,周邊的相關細節功能則由各個子類實現。

● 重構時,模板方法模式是一個經常使用的模式,把相同的程式碼抽取到父類中,然後通過鉤子函式(見“模板方法模式的擴充套件”)約束其行為。

 

5.建造者模式(Builder Pattern)

定義:Separate the construction of a complex object from its representation so that the same construction process can create different representations.(將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。)

● Product產品類

通常是實現了模板方法模式,也就是有模板方法和基本方法,例子中的BenzModel和BMWModel就屬於產品類。

● Builder抽象建造者

規範產品的組建,一般是由子類實現。例子中的CarBuilder就屬於抽象建造者。

● ConcreteBuilder具體建造者

實現抽象類定義的所有方法,並且返回一個組建好的物件。例子中的BenzBuilder和BMWBuilder就屬於具體建造者。

● Director導演類

負責安排已有模組的順序,然後告訴Builder開始建造

使用場景:

● 相同的方法,不同的執行順序,產生不同的事件結果時,可以採用建造者模式。

● 多個部件或零件,都可以裝配到一個物件中,但是產生的執行結果又不相同時,則可以使用該模式。

● 產品類非常複雜,或者產品類中的呼叫順序不同產生了不同的效能,這個時候使用建造者模式非常合適。

 

建造者模式與工廠模式的不同:

建造者模式最主要的功能是基本方法的呼叫順序安排,這些基本方法已經實現了,順序不同產生的物件也不同;

工廠方法則重點是建立,建立零件是它的主要職責,組裝順序則不是它關心的。

 

 

 

6.代理模式(Proxy Pattern)

定義:Provide a surrogate or placeholder for another object to control access to it.(為其他物件提供一種代理以控制對這個物件的訪問。)

● Subject抽象主題角色

抽象主題類可以是抽象類也可以是介面,是一個最普通的業務型別定義,無特殊要求。

● RealSubject具體主題角色

也叫做被委託角色、被代理角色。它才是冤大頭,是業務邏輯的具體執行者。

● Proxy代理主題角色

也叫做委託類、代理類。它負責對真實角色的應用,把所有抽象主題類定義的方法限制委託給真實主題角色實現,並且在真實主題角色處理完畢前後做預處理和善後處理工作。

 

普通代理和強制代理:

普通代理就是我們要知道代理的存在,也就是類似的GamePlayerProxy這個類的存在,然後才能訪問;

強制代理則是呼叫者直接呼叫真實角色,而不用關心代理是否存在,其代理的產生是由真實角色決定的。

普通代理:

在該模式下,呼叫者只知代理而不用知道真實的角色是誰,遮蔽了真實角色的變更對高層模組的影響,真實的主題角色想怎麼修改就怎麼修改,對高層次的模組沒有任何的影響,只要你實現了介面所對應的方法,該模式非常適合對擴充套件性要求較高的場合。

 

強制代理:

強制代理的概念就是要從真實角色查詢到代理角色,不允許直接訪問真實角色。高層模組只要呼叫getProxy就可以訪問真實角色的所有方法,它根本就不需要產生一個代理出來,代理的管理已經由真實角色自己完成。

 

動態代理:

根據被代理的介面生成所有的方法,也就是說給定一個介面,動態代理會宣稱“我已經實現該介面下的所有方法了”。

兩條獨立發展的線路。動態代理實現代理的職責,業務邏輯Subject實現相關的邏輯功能,兩者之間沒有必然的相互耦合的關係。通知Advice從另一個切面切入,最終在高層模組也就是Client進行耦合,完成邏輯的封裝任務。

 

動態代理呼叫過程示意圖:

動態代理的意圖:橫切面程式設計,在不改變我們已有程式碼結構的情況下增強或控制物件的行為。 

首要條件:被代理的類必須要實現一個介面。

7.原型模式(Prototype Pattern)

定義:Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.(用原型例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件。)

 

原型模式通用程式碼:

複製程式碼

public class PrototypeClass  implements Cloneable{
     //覆寫父類Object方法
     @Override
     public PrototypeClass clone(){
             PrototypeClass prototypeClass = null;
             try {
                    prototypeClass = (PrototypeClass)super.clone();
             } catch (CloneNotSupportedException e) {
                    //異常處理
             }
             return prototypeClass;
     }
}

複製程式碼

 

原型模式實際上就是實現Cloneable介面,重寫clone()方法。

使用原型模式的優點:

● 效能優良

原型模式是在記憶體二進位制流的拷貝,要比直接new一個物件效能好很多,特別是要在一個迴圈體內產生大量的物件時,原型模式可以更好地體現其優點。

● 逃避建構函式的約束

這既是它的優點也是缺點,直接在記憶體中拷貝,建構函式是不會執行的(參見13.4節)。

使用場景:

● 資源優化場景

類初始化需要消化非常多的資源,這個資源包括資料、硬體資源等。

● 效能和安全要求的場景

通過new產生一個物件需要非常繁瑣的資料準備或訪問許可權,則可以使用原型模式。

● 一個物件多個修改者的場景

一個物件需要提供給其他物件訪問,而且各個呼叫者可能都需要修改其值時,可以考慮使用原型模式拷貝多個物件供呼叫者使用。

 

淺拷貝和深拷貝:

淺拷貝:Object類提供的方法clone只是拷貝本物件,其物件內部的陣列、引用物件等都不拷貝,還是指向原生物件的內部元素地址,這種拷貝就叫做淺拷貝,其他的原始型別比如int、long、char、string(當做是原始型別)等都會被拷貝。

注意: 使用原型模式時,引用的成員變數必須滿足兩個條件才不會被拷貝:一是類的成員變數,而不是方法內變數;二是必須是一個可變的引用物件,而不是一個原始型別或不可變物件。

深拷貝:對私有的類變數進行獨立的拷貝    

  如:thing.arrayList = (ArrayList<String>)this.arrayList.clone();

8.中介者模式

定義:Define an object that encapsulates how a set of objects interact.Mediator promotes loose coupling by keeping objects from referring to each other explicitly,and it lets you vary their interaction independently.(用一箇中介物件封裝一系列的物件互動,中介者使各物件不需要顯示地相互作用,從而使其耦合鬆散,而且可以獨立地改變它們之間的互動。)

● Mediator 抽象中介者角色

抽象中介者角色定義統一的介面,用於各同事角色之間的通訊。

● Concrete Mediator 具體中介者角色

具體中介者角色通過協調各同事角色實現協作行為,因此它必須依賴於各個同事角色。

● Colleague 同事角色

每一個同事角色都知道中介者角色,而且與其他的同事角色通訊的時候,一定要通過中介者角色協作。每個同事類的行為分為兩種:一種是同事本身的行為,比如改變物件本身的狀態,處理自己的行為等,這種行為叫做自發行為(Self-Method),與其他的同事類或中介者沒有任何的依賴;第二種是必須依賴中介者才能完成的行為,叫做依賴方法(Dep-Method)。

 

通用抽象中介者程式碼:

複製程式碼

public abstract class Mediator {
     //定義同事類
     protected ConcreteColleague1 c1;
     protected ConcreteColleague2 c2;
     //通過getter/setter方法把同事類注入進來
     public ConcreteColleague1 getC1() {
             return c1;
     }
     public void setC1(ConcreteColleague1 c1) {
             this.c1 = c1;
     }
     public ConcreteColleague2 getC2() {
             return c2;
}
     public void setC2(ConcreteColleague2 c2) {
             this.c2 = c2;
     }
     //中介者模式的業務邏輯
     public abstract void doSomething1();
     public abstract void doSomething2();
}

複製程式碼

 

ps:使用同事類注入而不使用抽象注入的原因是因為抽象類中不具有每個同事類必須要完成的方法。即每個同事類中的方法各不相同。

 

問:為什麼同事類要使用建構函式注入中介者,而中介者使用getter/setter方式注入同事類呢?

這是因為同事類必須有中介者,而中介者卻可以只有部分同事類。

 

使用場景:

中介者模式適用於多個物件之間緊密耦合的情況,緊密耦合的標準是:在類圖中出現了蜘蛛網狀結構,即每個類都與其他的類有直接的聯絡。

9.命令模式

定義:Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.(將一個請求封裝成一個物件,從而讓你使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。)

● Receive接收者角色

該角色就是幹活的角色,命令傳遞到這裡是應該被執行的,具體到我們上面的例子中就是Group的三個實現類(需求組,美工組,程式碼組)。

● Command命令角色

需要執行的所有命令都在這裡宣告。

● Invoker呼叫者角色

接收到命令,並執行命令。在例子中,我(專案經理)就是這個角色。

使用場景:

認為是命令的地方就可以採用命令模式,例如,在GUI開發中,一個按鈕的點選是一個命令,可以採用命令模式;模擬DOS命令的時候,當然也要採用命令模式;觸發-反饋機制的處理等。

 

10.責任鏈模式

定義:Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.(使多個物件都有機會處理請求,從而避免了請求的傳送者和接受者之間的耦合關係。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有物件處理它為止。)

 

抽象處理者的程式碼:

複製程式碼

public abstract class Handler {
     private Handler nextHandler;
     //每個處理者都必須對請求做出處理
     public final Response handleMessage(Request request){
             Response response = null;  
             //判斷是否是自己的處理級別
             if(this.getHandlerLevel().equals(request.getRequestLevel())){
                    response = this.echo(request);
             }else{  //不屬於自己的處理級別
                    //判斷是否有下一個處理者
                    if(this.nextHandler != null){
                            response = this.nextHandler.handleMessage(request);
                    }else{
                            //沒有適當的處理者,業務自行處理
                    }
             }
             return response;
     }
     //設定下一個處理者是誰
     public void setNext(Handler _handler){
             this.nextHandler = _handler;
     }
     //每個處理者都有一個處理級別
     protected abstract Level getHandlerLevel();
     //每個處理者都必須實現處理任務
     protected abstract Response echo(Request request);
}

複製程式碼

 

抽象的處理者實現三個職責:

一是定義一個請求的處理方法handleMessage,唯一對外開放的方法;

二是定義一個鏈的編排方法setNext,設定下一個處理者;

三是定義了具體的請求者必須實現的兩個方法:定義自己能夠處理的級別getHandlerLevel和具體的處理任務echo。

注意事項:

鏈中節點數量需要控制,避免出現超長鏈的情況,一般的做法是在Handler中設定一個最大節點數量,在setNext方法中判斷是否已經是超過其閾值,超過則不允許該鏈建立,避免無意識地破壞系統性能。

 

11.裝飾模式(Decorator Pattern)

定義:Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.(動態地給一個物件新增一些額外的職責。就增加功能來說,裝飾模式相比生成子類更為靈活。)

 

● Component抽象構件

Component是一個介面或者是抽象類,就是定義我們最核心的物件,也就是最原始的物件,如上面的成績單。

注意:在裝飾模式中,必然有一個最基本、最核心、最原始的介面或抽象類充當Component抽象構件。

● ConcreteComponent 具體構件

ConcreteComponent是最核心、最原始、最基本的介面或抽象類的實現,你要裝飾的就是它。

● Decorator裝飾角色

一般是一個抽象類,做什麼用呢?實現介面或者抽象方法,它裡面可不一定有抽象的方法呀,在它的屬性裡必然有一個private變數指向Component抽象構件。

● 具體裝飾角色

ConcreteDecoratorA和ConcreteDecoratorB是兩個具體的裝飾類,你要把你最核心的、最原始的、最基本的東西裝飾成其他東西,上面的例子就是把一個比較平庸的成績單裝飾成家長認可的成績單。

使用場景:

● 需要擴充套件一個類的功能,或給一個類增加附加功能。

● 需要動態地給一個物件增加功能,這些功能可以再動態地撤銷。

● 需要為一批的兄弟類進行改裝或加裝功能,當然是首選裝飾模式。

 

12.策略模式(Strategy Pattern)

定義:Define a family of algorithms,encapsulate each one,and make them interchangeable.(定義一組演算法,將每個演算法都封裝起來,並且使它們之間可以互換。)

 

● Context封裝角色

它也叫做上下文角色,起承上啟下封裝作用,遮蔽高層模組對策略、演算法的直接訪問,封裝可能存在的變化。

● Strategy抽象策略角色

策略、演算法家族的抽象,通常為介面,定義每個策略或演算法必須具有的方法和屬性。各位看官可能要問了,類圖中的AlgorithmInterface是什麼意思,嘿嘿,algorithm是“運演算法則”的意思,結合起來意思就明白了吧。

● ConcreteStrategy具體策略角色(多個)

實現抽象策略中的操作,該類含有具體的演算法。

使用場景:

● 多個類只有在演算法或行為上稍有不同的場景。

● 演算法需要自由切換的場景。

● 需要遮蔽演算法規則的場景。

注意事項:具體策略數量超過4個,則需要考慮使用混合模式

 

策略模式擴充套件:策略列舉

複製程式碼

public enum Calculator {
     //加法運算
     ADD("+"){
             public int exec(int a,int b){
                    return a+b;
             }
     },
     //減法運算
     SUB("-"){
             public int exec(int a,int b){
                    return a - b;
             }
     };
     String value = "";
     //定義成員值型別
     private Calculator(String _value){
             this.value = _value;
     }
     //獲得列舉成員的值
     public String getValue(){
             return this.value;
     }
     //宣告一個抽象函式
     public abstract int exec(int a,int b);
}

複製程式碼

 

定義:

● 它是一個列舉。

● 它是一個濃縮了的策略模式的列舉。

注意:

受列舉型別的限制,每個列舉項都是public、final、static的,擴充套件性受到了一定的約束,因此在系統開發中,策略列舉一般擔當不經常發生變化的角色。

致命缺陷:

所有的策略都需要暴露出去,由客戶端決定使用哪一個策略。

 

13.介面卡模式(Adapter Pattern)

定義:Convert the interface of a class into another interface clients expect.Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.(將一個類的介面變換成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠在一起工作。)

類介面卡:

 

● Target目標角色

該角色定義把其他類轉換為何種介面,也就是我們的期望介面,例子中的IUserInfo介面就是目標角色。

● Adaptee源角色

你想把誰轉換成目標角色,這個“誰”就是源角色,它是已經存在的、執行良好的類或物件,經過介面卡角色的包裝,它會成為一個嶄新、靚麗的角色。

● Adapter介面卡角色

介面卡模式的核心角色,其他兩個角色都是已經存在的角色,而介面卡角色是需要新建立的,它的職責非常簡單:把源角色轉換為目標角色,怎麼轉換?通過繼承或是類關聯的方式。

使用場景

你有動機修改一個已經投產中的介面時,介面卡模式可能是最適合你的模式。比如系統擴充套件了,需要使用一個已有或新建立的類,但這個類又不符合系統的介面,怎麼辦?使用介面卡模式,這也是我們例子中提到的。

注意事項:

詳細設計階段不要考慮使用介面卡模式,使用主要場景為擴充套件應用中。

 

物件介面卡:

 物件介面卡和類介面卡的區別:

類介面卡是類間繼承,物件介面卡是物件的合成關係,也可以說是類的關聯關係,這是兩者的根本區別。(實際專案中物件介面卡使用到的場景相對比較多)。

 

 

14.迭代器模式(Iterator Pattern)

定義:Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.(它提供一種方法訪問一個容器物件中各個元素,而又不需暴露該物件的內部細節。)

● Iterator抽象迭代器

抽象迭代器負責定義訪問和遍歷元素的介面,而且基本上是有固定的3個方法:first()獲得第一個元素,next()訪問下一個元素,isDone()是否已經訪問到底部(Java叫做hasNext()方法)。

● ConcreteIterator具體迭代器

具體迭代器角色要實現迭代器介面,完成容器元素的遍歷。

● Aggregate抽象容器

容器角色負責提供建立具體迭代器角色的介面,必然提供一個類似createIterator()這樣的方法,在Java中一般是iterator()方法。

● Concrete Aggregate具體容器

具體容器實現容器介面定義的方法,創建出容納迭代器的物件。

ps:迭代器模式已經被淘汰,java中已經把迭代器運用到各個聚集類(collection)中了,使用java自帶的迭代器就已經滿足我們的需求了。

15.組合模式((Composite Pattern))

定義:Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.(將物件組合成樹形結構以表示“部分-整體”的層次結構,使得使用者對單個物件和組合物件的使用具有一致性。)

 

● Component抽象構件角色

定義參加組合物件的共有方法和屬性,可以定義一些預設的行為或屬性,比如我們例子中的getInfo就封裝到了抽象類中。

● Leaf葉子構件

葉子物件,其下再也沒有其他的分支,也就是遍歷的最小單位。

● Composite樹枝構件

樹枝物件,它的作用是組合樹枝節點和葉子節點形成一個樹形結構。

 

樹枝構件的通用程式碼:

複製程式碼

public class Composite extends Component {
     //構件容器
     private ArrayList<Component> componentArrayList = new ArrayList<Component>();
     //增加一個葉子構件或樹枝構件
     public void add(Component component){
             this.componentArrayList.add(component);
     }
     //刪除一個葉子構件或樹枝構件
     public void remove(Component component){
this.componentArrayList.remove(component);
     }
     //獲得分支下的所有葉子構件和樹枝構件
     public ArrayList<Component> getChildren(){
             return this.componentArrayList;
     }
}

複製程式碼

 

使用場景:

● 維護和展示部分-整體關係的場景,如樹形選單、檔案和資料夾管理。

● 從一個整體中能夠獨立出部分模組或功能的場景。

注意:

只要是樹形結構,就考慮使用組合模式。

16.觀察者模式(Observer Pattern)

定義:Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically.(定義物件間一種一對多的依賴關係,使得每當一個物件改變狀態,則所有依賴於它的物件都會得到通知並被自動更新。)

 

● Subject被觀察者

定義被觀察者必須實現的職責,它必須能夠動態地增加、取消觀察者。它一般是抽象類或者是實現類,僅僅完成作為被觀察者必須實現的職責:管理觀察者並通知觀察者。

● Observer觀察者

觀察者接收到訊息後,即進行update(更新方法)操作,對接收到的資訊進行處理。

● ConcreteSubject具體的被觀察者

定義被觀察者自己的業務邏輯,同時定義對哪些事件進行通知。

● ConcreteObserver具體的觀察者

每個觀察在接收到訊息後的處理反應是不同,各個觀察者有自己的處理邏輯。

 

被觀察者通用程式碼:

複製程式碼

public abstract class Subject {
     //定義一個觀察者陣列
     private Vector<Observer> obsVector = new Vector<Observer>();
     //增加一個觀察者
     public void addObserver(Observer o){
             this.obsVector.add(o);
     }
     //刪除一個觀察者
     public void delObserver(Observer o){
             this.obsVector.remove(o);
     }
     //通知所有觀察者
     public void notifyObservers(){
             for(Observer o:this.obsVector){
                     o.update();
}
     }
}

複製程式碼

 

使用場景:

● 關聯行為場景。需要注意的是,關聯行為是可拆分的,而不是“組合”關係。

● 事件多級觸發場景。

● 跨系統的訊息交換場景,如訊息佇列的處理機制。

注意:

● 廣播鏈的問題

在一個觀察者模式中最多出現一個物件既是觀察者也是被觀察者,也就是說訊息最多轉發一次(傳遞兩次)。

● 非同步處理問題

觀察者比較多,而且處理時間比較長,採用非同步處理來考慮執行緒安全和佇列的問題。

 

17.門面模式(Facade Pattern)

定義:Provide a unified interface to a set of interfaces in a subsystem.Facade defines a higher-level interface that makes the subsystem easier to use.(要求一個子系統的外部與其內部的通訊必須通過一個統一的物件進行。門面模式提供一個高層次的介面,使得子系統更易於使用。)

 

● Facade門面角色
客戶端可以呼叫這個角色的方法。此角色知曉子系統的所有功能和責任。一般情況下,本角色會將所有從客戶端發來的請求委派到相應的子系統去,也就說該角色沒有實際的業務邏輯,只是一個委託類。
● subsystem子系統角色
可以同時有一個或者多個子系統。每一個子系統都不是一個單獨的類,而是一個類的集合。子系統並不知道門面的存在。對於子系統而言,門面僅僅是另外一個客戶端而已。

 

使用場景:

● 為一個複雜的模組或子系統提供一個供外界訪問的介面

● 子系統相對獨立——外界對子系統的訪問只要黑箱操作即可

● 預防低水平人員帶來的風險擴散

注意:

●一個子系統可以有多個門面

●門面不參與子系統內的業務邏輯

18.備忘錄模式(Memento Pattern)

定義:Without violating encapsulation,capture and externalize an object's internal state so that the object can be restored to this state later.(在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。這樣以後就可將該物件恢復到原先儲存的狀態。)

● Originator發起人角色

記錄當前時刻的內部狀態,負責定義哪些屬於備份範圍的狀態,負責建立和恢復備忘錄資料。

● Memento備忘錄角色(簡單的javabean)

負責儲存Originator發起人物件的內部狀態,在需要的時候提供發起人需要的內部狀態。

● Caretaker備忘錄管理員角色(簡單的javabean)

對備忘錄進行管理、儲存和提供備忘錄。

 

使用場景:

● 需要儲存和恢復資料的相關狀態場景。

● 提供一個可回滾(rollback)的操作。

● 需要監控的副本場景中。

● 資料庫連線的事務管理就是用的備忘錄模式。

注意:

●備忘錄的生命期

●備忘錄的效能

   不要在頻繁建立備份的場景中使用備忘錄模式(比如一個for迴圈中)。    

 

clone方式備忘錄:

 

● 發起人角色融合了發起人角色和備忘錄角色,具有雙重功效

 

多狀態的備忘錄模式

 

● 增加了一個BeanUtils類,其中backupProp是把發起人的所有屬性值轉換到HashMap中,方便備忘錄角色儲存。restoreProp方法則是把HashMap中的值返回到發起人角色中。

 

BeanUtil工具類程式碼:

複製程式碼

public class BeanUtils {
     //把bean的所有屬性及數值放入到Hashmap中
     public static HashMap<String,Object> backupProp(Object bean){
             HashMap<String,Object> result = new HashMap<String,Object>();
             try {
                     //獲得Bean描述
                     BeanInfo beanInfo=Introspector.getBeanInfo(bean.getClass());
                     //獲得屬性描述
                     PropertyDescriptor[] descriptors=beanInfo.getPropertyDescriptors();
                     //遍歷所有屬性
                     for(PropertyDescriptor des:descriptors){
                             //屬性名稱
                             String fieldName = des.getName();
                             //讀取屬性的方法
                             Method getter = des.getReadMethod();
                             //讀取屬性值
                             Object fieldValue=getter.invoke(bean,new Object[]{});
                    if(!fieldName.equalsIgnoreCase("class")){
                             result.put(fieldName, fieldValue);
                    }
               }
          } catch (Exception e) {
               //異常處理
          }
          return result;
     }
     //把HashMap的值返回到bean中
     public static void restoreProp(Object bean,HashMap<String,Object> propMap){
try {
               //獲得Bean描述
               BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
               //獲得屬性描述
               PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
               //遍歷所有屬性
               for(PropertyDescriptor des:descriptors){
                    //屬性名稱
                    String fieldName = des.getName();
                    //如果有這個屬性
                    if(propMap.containsKey(fieldName)){
                         //寫屬性的方法
                         Method setter = des.getWriteMethod();
                         setter.invoke(bean, new Object[]{propMap.get(fieldName)});
                    }
               }
          } catch (Exception e) {
               //異常處理
               System.out.println("shit");
               e.printStackTrace();
          }
     }
}

複製程式碼

 

多備份的備忘錄:略

封裝得更好一點:保證只能對發起人可讀

 

●建立一個空介面IMemento——什麼方法屬性都沒有的介面,然後在發起人Originator類中建立一個內建類(也叫做類中類)Memento實現IMemento介面,同時也實現自己的業務邏輯。

 

19.訪問者模式(Visitor Pattern)

定義:Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates. (封裝一些作用於某種資料結構中的各元素的操作,它可以在不改變資料結構的前提下定義作用於這些元素的新的操作。)

 

● Visitor——抽象訪問者

抽象類或者介面,宣告訪問者可以訪問哪些元素,具體到程式中就是visit方法的引數定義哪些物件是可以被訪問的。

● ConcreteVisitor——具體訪問者

它影響訪問者訪問到一個類後該怎麼幹,要做什麼事情。

● Element——抽象元素

介面或者抽象類,宣告接受哪一類訪問者訪問,程式上是通過accept方法中的引數來定義的。

● ConcreteElement——具體元素

實現accept方法,通常是visitor.visit(this),基本上都形成了一種模式了。

● ObjectStruture——結構物件

元素產生者,一般容納在多個不同類、不同介面的容器,如List、Set、Map等,在專案中,一般很少抽象出這個角色。

 

使用場景:

● 一個物件結構包含很多類物件,它們有不同的介面,而你想對這些物件實施一些依賴於其具體類的操作,也就說是用迭代器模式已經不能勝任的情景。

● 需要對一個物件結構中的物件進行很多不同並且不相關的操作,而你想避免讓這些操作“汙染”這些物件的類。

20.狀態模式(複雜)

定義: