23種設計模式

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()方法。java

使用原型模式的優勢:
● 性能優良
原型模式是在內存二進制流的拷貝,要比直接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.狀態模式(複雜)

定義:Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(當一個對象內在狀態改變時容許其改變行爲,這個對象看起來像改變了其類。)
● State——抽象狀態角色
接口或抽象類,負責對象狀態定義,而且封裝環境角色以實現狀態切換。
● ConcreteState——具體狀態角色
每個具體狀態必須完成兩個職責:本狀態的行爲管理以及趨向狀態處理,通俗地說,就是本狀態下要作的事情,以及本狀態如何過渡到其餘狀態。
● Context——環境角色
定義客戶端須要的接口,而且負責具體狀態的切換。
 
使用場景:
● 行爲隨狀態改變而改變的場景
這也是狀態模式的根本出發點,例如權限設計,人員的狀態不一樣即便執行相同的行爲結果也會不一樣,在這種狀況下須要考慮使用狀態模式。
● 條件、分支判斷語句的替代者
 
注意:
狀態模式適用於當某個對象在它的狀態發生改變時,它的行爲也隨着發生比較大的變化,也就是說在行爲受狀態約束的狀況下可使用狀態模式,並且使用時對象的狀態最好不要超過5個。
 

21.解釋器模式(Interpreter Pattern)(少用)

定義:Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.(給定一門語言,定義它的文法的一種表示,並定義一個解釋器,該解釋器使用該表示來解釋語言中的句子。)
 
● AbstractExpression——抽象解釋器
具體的解釋任務由各個實現類完成,具體的解釋器分別由TerminalExpression和Non-terminalExpression完成。
● TerminalExpression——終結符表達式
實現與文法中的元素相關聯的解釋操做,一般一個解釋器模式中只有一個終結符表達式,但有多個實例,對應不一樣的終結符。具體到咱們例子就是VarExpression類,表達式中的每一個終結符都在棧中產生了一個VarExpression對象。
● NonterminalExpression——非終結符表達式
文法中的每條規則對應於一個非終結表達式,具體到咱們的例子就是加減法規則分別對應到AddExpression和SubExpression兩個類。非終結符表達式根據邏輯的複雜程度而增長,原則上每一個文法規則都對應一個非終結符表達式。
● Context——環境角色
具體到咱們的例子中是採用HashMap代替。
 
使用場景:
● 重複發生的問題可使用解釋器模式
● 一個簡單語法須要解釋的場景
 
注意:
儘可能不要在重要的模塊中使用解釋器模式,不然維護會是一個很大的問題。在項目中可使用shell、JRuby、Groovy等腳本語言來代替解釋器模式,彌補Java編譯型語言的不足。

22.享元模式(Flyweight Pattern)

定義:Use sharing to support large numbers of fine-grained objects efficiently.(使用共享對象可有效地支持大量的細粒度的對象。)
對象的信息分爲兩個部分:內部狀態(intrinsic)與外部狀態(extrinsic)。
● 內部狀態
內部狀態是對象可共享出來的信息,存儲在享元對象內部而且不會隨環境改變而改變。
● 外部狀態
外部狀態是對象得以依賴的一個標記,是隨環境改變而改變的、不能夠共享的狀態。
 
● Flyweight——抽象享元角色
它簡單地說就是一個產品的抽象類,同時定義出對象的外部狀態和內部狀態的接口或實現。
● ConcreteFlyweight——具體享元角色
具體的一個產品類,實現抽象角色定義的業務。該角色中須要注意的是內部狀態處理應該與環境無關,不該該出現一個操做改變了內部狀態,同時修改了外部狀態,這是絕對不容許的。
● unsharedConcreteFlyweight——不可共享的享元角色
不存在外部狀態或者安全要求(如線程安全)不可以使用共享技術的對象,該對象通常不會出如今享元工廠中。
● FlyweightFactory——享元工廠
職責很是簡單,就是構造一個池容器,同時提供從池中得到對象的方法。
 
享元工廠的代碼:
public class FlyweightFactory {
     //定義一個池容器
     private static  HashMap<String,Flyweight> pool= new HashMap<String,Flyweight>();
     //享元工廠
     public static Flyweight getFlyweight(String Extrinsic){
             //須要返回的對象
             Flyweight flyweight = null;
             //在池中沒有該對象
             if(pool.containsKey(Extrinsic)){
                     flyweight = pool.get(Extrinsic);
             }else{
                     //根據外部狀態建立享元對象
                     flyweight = new ConcreteFlyweight1(Extrinsic);
                     //放置到池中
                     pool.put(Extrinsic, flyweight);
             }
             return flyweight;
     }
}

 

使用場景:
● 系統中存在大量的類似對象。
● 細粒度的對象都具有較接近的外部狀態,並且內部狀態與環境無關,也就是說對象沒有特定身份。
● 須要緩衝池的場景。
注意:
● 享元模式是線程不安全的,只有依靠經驗,在須要的地方考慮一下線程安全,在大部分場景下不用考慮。對象池中的享元對象儘可能多,多到足夠知足爲止。
● 性能安全:外部狀態最好以java的基本類型做爲標誌,如String,int,能夠提升效率。

23.橋樑模式(Bridge Pattern)

定義:Decouple an abstraction from its implementation so that the two can vary independently.(將抽象和實現解耦,使得二者能夠獨立地變化。)
 
● Abstraction——抽象化角色
它的主要職責是定義出該角色的行爲,同時保存一個對實現化角色的引用,該角色通常是抽象類。
● Implementor——實現化角色
它是接口或者抽象類,定義角色必需的行爲和屬性。
● RefinedAbstraction——修正抽象化角色
它引用實現化角色對抽象化角色進行修正。
● ConcreteImplementor——具體實現化角色
它實現接口或抽象類定義的方法和屬性。
 
使用場景:
● 不但願或不適用使用繼承的場景
● 接口或抽象類不穩定的場景
● 重用性要求較高的場景
 
注意:
發現類的繼承有N層時,能夠考慮使用橋樑模式。橋樑模式主要考慮如何拆分抽象和實現。
相關文章
相關標籤/搜索