【硬核】23種設計模式娓娓道來,助你優雅的編寫出漂亮代碼!

你們好,我是小羽。面試

咱們平時使用的每個技術棧的原理或者源碼都或多或少與設計模式的理念有關聯,也能夠這麼說,只有更好的掌握了設計模式,咱們的代碼編寫才能更規範、簡潔,效率更高。算法

其次,設計模式大多都是通過咱們的前輩的經驗反覆總結而成,站在巨人的肩膀上,吸取他們的經驗教訓,咱們的編碼之路纔會走的更長久。數據庫

同時,在咱們的面試過程當中也是加分的選項,你若是將設計模式能跟面試官娓娓道來,面試官確定會對你另眼相看的。工做中,擁有良好的設計模式思想,對於項目的開發也會有很大的幫助。編程

接下來,跟着小羽一塊兒來看看咱們須要瞭解的設計模式都有哪些呢~設計模式

前言

整體來講設計模式分爲三大類:數組

_建立型模式:_工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。緩存

_結構型模式:_適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。安全

_行爲型模式:_策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。數據結構

單例模式

概念

確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例。框架

使用場景

  • 要求生成惟一序列號的環境;

  • 在整個項目中須要一個共享訪問點或共享數據,例如一個Web頁面上的計數器,能夠不用把每次刷新都記錄到數據庫中,使用單例模式保持計數器的值,並確保是線程安全的;

  • 建立一個對象須要消耗的資源過多,如要訪問IO和數據庫等資源;

  • 須要定義大量的靜態常量和靜態方法(如工具類)的環境,能夠採用單例模式(固然,也能夠直接聲明爲static的方式)。

代碼示例

線程安全:

`public class Singleton {`
 `private static final Singleton singleton = new Singleton();`
 `//限制產生多個對象`
 `private Singleton(){`
 `}`
 `//經過該方法得到實例對象`
 `public static Singleton getSingleton(){`
 `return singleton;`
 `}`
 `//類中其餘方法,儘可能是 static`
 `public static void doSomething(){`
 `}`
`}`

線程不安全:

`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 來實現。

工廠模式

概念

定義一個用於建立對象的接口,讓子類決定實例化哪個類。工廠方法使一個類的實例化延遲到其子類。

使用場景

jdbc 鏈接數據庫,硬件訪問,下降對象的產生和銷燬

結構

_簡單工廠模式:_一個模塊僅須要一個工廠類,沒有必要把它產生出來,使用靜態的方法

_多個工廠類:_每一個人種(具體的產品類)都對應了一個建立者,每一個建立者獨立負責建立對應的產品對象,很是符合單一職責原則

_代替單例模式:_單例模式的核心要求就是在內存中只有一個對象,經過工廠方法模式也能夠只在內存中生產一個對象

_延遲初始化:_ProductFactory 負責產品類對象的建立工做,而且經過 prMap 變量產生一個緩存,對須要再次被重用的對象保留

代碼示例

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;`
 `}`
`}`

抽象工廠模式

概念

爲建立一組相關或相互依賴的對象提供一個接口,並且無須指定它們的具體類。

使用場景

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

涉及不一樣操做系統的時候,均可以考慮使用抽象工廠模式。

代碼示例

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

模板方法模式

概念

定義一個操做中的算法的框架,而將一些步驟延遲到子類中。使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。

使用場景

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

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

  • 重構時,模板方法模式是一個常用的模式,把相同的代碼抽取到父類中,而後經過鉤子函數(見「模板方法模式的擴展」)約束其行爲。

結構

抽象模板:AbstractClass 爲抽象模板,它的方法分爲兩類:

一、基本方法:也叫作基本操做,是由子類實現的方法,而且在模板方法被調用。

二、模板方法:能夠有一個或幾個,通常是一個具體方法,也就是一個框架,實現對基本方法的調度,完成固定的邏輯。

注意: 爲了防止惡意的操做,通常模板方法都加上 final 關鍵字,不容許被覆寫

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

代碼示例

`package templateMethod;`
`public class TemplateMethodPattern`
`{`
 `public static void main(String[] args)`
 `{`
 `AbstractClass tm=new ConcreteClass();`
 `tm.TemplateMethod();`
 `}`
`}`
`//抽象類`
`abstract class AbstractClass`
`{`
 `public void TemplateMethod() //模板方法`
 `{`
 `SpecificMethod();`
 `abstractMethod1();`
 `abstractMethod2();`
 `}`
 `public void SpecificMethod() //具體方法`
 `{`
 `System.out.println("抽象類中的具體方法被調用...");`
 `}`
 `public abstract void abstractMethod1(); //抽象方法1`
 `public abstract void abstractMethod2(); //抽象方法2`
`}`
`//具體子類`
`class ConcreteClass extends AbstractClass`
`{`
 `public void abstractMethod1()`
 `{`
 `System.out.println("抽象方法1的實現被調用...");`
 `}`
 `public void abstractMethod2()`
 `{`
 `System.out.println("抽象方法2的實現被調用...");`
 `}`
`}`

建造者模式

概念

將一個複雜對象的構建與它的表示分離,使得一樣的構建過程能夠建立不一樣的表示。

使用場景

  • 相同的方法,不一樣的執行順序,產生不一樣的事件結果時,能夠採用建造者模式。

  • 多個部件或零件,均可以裝配到一個對象中,可是產生的運行結果又不相同時,則可使用該模式。

  • 產品類很是複雜,或者產品類中的調用順序不一樣產生了不一樣的效能,這個時候使用建造者模式很是合適。

結構

_Product 產品類:_一般是實現了模板方法模式,也就是有模板方法和基本方法。

_Builder 抽象建造者:_規範產品的組建,通常是由子類實現。

_ConcreteBuilder 具體建造者:_實現抽象類定義的全部方法,而且返回一個組建好的對象。

_Director 導演類:_負責安排已有模塊的順序,而後告訴 Builder 開始建造

代碼示例

`public class ConcreteProduct extends Builder {`
 `private Product product = new Product();`
 `//設置產品零件`
 `public void setPart(){`
 `/*`
 `* 產品類內的邏輯處理`
 `*/`
 `}` 
 `//組建一個產品`
 `public Product buildProduct() {`
 `return product;`
 `}`
`}`

代理模式

概念

爲其餘對象提供一種代理以控制對這個對象的訪問。

結構

_Subject 抽象主題角色:_抽象主題類能夠是抽象類也能夠是接口,是一個最普通的業務類型定義,無特殊要求。

_RealSubject 具體主題角色:_也叫作被委託角色、被代理角色。它纔是冤大頭,是業務邏輯的具體執行者。

_Proxy 代理主題角色:_也叫作委託類、代理類。它負責對真實角色的應用,把全部抽象主題類定義的方法、限制委託給真實主題角色實現,而且在真實主題角色處理完畢先後作預處理和藹後處理工做。

分類

_普通代理:_在該模式下,調用者只知代理而不用知道真實的角色是誰,屏蔽了真實角色的變動對高層模塊的影響,真實的主題角色想怎麼修改就怎麼修改,對高層次的模塊沒有任何的影響,只要你實現了接口所對應的方法,該模式很是適合對擴展性要求較高的場合。

_強制代理:_強制代理的概念就是要從真實角色查找到代理角色,不容許直接訪問真實角色。高層模塊只要調用 getProxy 就能夠訪問真實角色的全部方法,它根本就不須要產生一個代理出來,代理的管理已經由真實角色本身完成。

  • 區別:普通代理就是咱們要知道代理的存在,而後才能訪問;強制代理則是調用者直接調用真實角色,而不用關心代理是否存在,其代理的產生是由真實角色決定的。

_動態代理:_根據被代理的接口生成全部的方法,也就是說給定一個接口,動態代理會宣稱「我已經實現該接口下的全部方法了」。兩條獨立發展的線路。動態代理實現代理的職責,業務邏輯實現相關的邏輯功能,二者之間沒有必然的相互耦合的關係。通知從另外一個切面切入,最終在高層模塊進行耦合,完成邏輯的封裝任務。

  • 意圖:橫切面編程,在不改變咱們已有代碼結構的狀況下加強或控制對象的行爲。

  • 首要條件:被代理的類必需要實現一個接口。

代碼示例

`public Object getProxy(@Nullable ClassLoader classLoader) {`
 `if (logger.isTraceEnabled()) {`
 `logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());`
 `}`
 `Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);`
 `findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);`
 `return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);`
`}`

原型模式

概念

用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。

使用場景

_資源優化場景:_類初始化須要消化很是多的資源,這個資源包括數據、硬件資源等。

_性能和安全要求的場景:_經過 new 產生一個對象須要很是繁瑣的數據準備或訪問權限,則可使用原型模式。

_一個對象多個修改者的場景:_一個對象須要提供給其餘對象訪問,並且各個調用者可能都須要修改其值時,能夠、考慮使用原型模式拷貝多個對象供調用者使用。

優勢

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

_性能優良:_原型模式是在內存二進制流的拷貝,要比直接 new 一個對象性能好不少,特別是要在一個循環體內產生大量的對象時,原型模式能夠更好地體現其優勢。

_逃避構造函數的約束:_這既是它的優勢也是缺點,直接在內存中拷貝,構造函數是不會執行的。

代碼示例

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

中介者模式

概念

用一箇中介對象封裝一系列的對象交互,中介者使各對象不須要顯示地相互做用,從而使其耦合鬆散,並且能夠獨立地改變它們之間的交互。

使用場景

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

結構

_Mediator 抽象中介者角色:_抽象中介者角色定義統一的接口,用於各同事角色之間的通訊。

_Concrete Mediator 具體中介者角色:_具體中介者角色經過協調各同事角色實現協做行爲,所以它必須依賴於各個同事角色。

_Colleague 同事角色:_每個同事角色都知道中介者角色,並且與其餘的同事角色通訊的時候,必定要經過中介者角色協做。每一個同事類的行爲分爲兩種:一種是同事自己的行爲,好比改變對象自己的狀態,處理本身的行爲等,這種行爲叫作自發行爲(SelfMethod),與其餘的同事類或中介者沒有任何的依賴;第二種是必須依賴中介者才能完成的行爲,叫作依賴方法(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();`
`}`

命令模式

概念

將一個請求封裝成一個對象,從而讓你使用不一樣的請求把客戶端參數化,對請求排隊或者記錄請求日誌,能夠提供命令的撤銷和恢復功能。

使用場景

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

結構

_Receive 接收者角色:_該角色就是幹活的角色,命令傳遞到這裏是應該被執行的,具體到咱們上面的例子中就是 Group 的三個實現類(需求組,美工組,代碼組)。

_Command 命令角色:_須要執行的全部命令都在這裏聲明。

_Invoker 調用者角色:_接收到命令,並執行命令。在例子中,我(項目經理)就是這個角色。

代碼示例

`public class Invoker {`
 `private Command command;`
 `// 設值注入`
 `public void setCommand(Command command) {`
 `this.command = command;`
 `}`
 `// 執行命令`
 `public void action() {`
 `this.command.execute();`
 `}`
`}`

責任鏈模式

概念

使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有對象處理它爲止。

職責

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

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

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

三、定義了具體的請求者必須實現的兩個方法:定義本身可以處理的級別getHandlerLevel 和具體的處理任務 echo。

代碼示例

`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);`
`}`

注意事項

鏈中節點數量須要控制,避免出現超長鏈的狀況,通常的作法是在 Handler 中設置一個最大節點數量,在 setNext 方法中判斷是否已是超過其閾值,超過則不容許該鏈創建,避免無心識地破壞系統性能。

裝飾模式

概念

動態地給一個對象添加一些額外的職責。就增長功能來講,裝飾模式相比生成子類更爲靈活。

使用場景

  • 須要擴展一個類的功能,或給一個類增長附加功能。

  • 須要動態地給一個對象增長功能,這些功能能夠再動態地撤銷。

  • 須要爲一批的兄弟類進行改裝或加裝功能,固然是首選裝飾模式。

結構

_Component 抽象構件:_Component 是一個接口或者是抽象類,就是定義咱們最核心的對象,也就是最原始的對象。在裝飾模式中,必然有一個最基本、最核心、最原始的接口或抽象類充當Component 抽象構件。

_ConcreteComponent 具體構件:_ConcreteComponent 是最核心、最原始、最基本的接口或抽象類的實現,你要裝飾的就是它。

_Decorator 裝飾角色:_通常是一個抽象類,作什麼用呢?實現接口或者抽象方法,它裏面可不必定有抽象的方法呀,在它的屬性裏必然有一個 private 變量指向 Component 抽象構件。

_具體裝飾角色:_兩個具體的裝飾類,你要把你最核心的、最原始的、最基本的東西裝飾成其餘東西。

代碼示例

`/**`
 `* 裝飾角色`
 `*/`
`@Data`
`@AllArgsConstructor`
`@NoArgsConstructor`
`@Log`
`class BufferedReader implements Reader{`
 `private  Reader reader;`
 `@Override`
 `public void read() {`
 `reader.read();`
 `}`
 `public void readLine(){`
 `read();`
 `log.info("而且僅僅讀取一行");`
 `}`
`}`

策略模式

概念

定義一組算法,將每一個算法都封裝起來,而且使它們之間能夠互換。

使用場景

  • 多個類只有在算法或行爲上稍有不一樣的場景。

  • 算法須要自由切換的場景。

  • 須要屏蔽算法規則的場景。

  • 具體策略數量超過 4 個,則須要考慮使用混合模式

結構

_Context 封裝角色:_它也叫作上下文角色,起承上啓下封裝做用,屏蔽高層模塊對策略、算法的直接訪問,封裝可能存在的變化。

_Strategy 抽象策略角色:_策略、算法家族的抽象,一般爲接口,定義每一個策略或算法必須具備的方法和屬性。

_ConcreteStrategy 具體策略角色:_實現抽象策略中的操做,該類含有具體的算法。

代碼示例

`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);`
`}`

適配器模式

概念

將一個類的接口變換成客戶端所期待的另外一種接口,從而使本來因接口不匹配而沒法在一塊兒工做的兩個類可以在一塊兒工做。

使用場景

你有動機修改一個已經投產中的接口時,適配器模式多是最適合你的模式。好比系統擴展了,須要使用一個已有或新創建的類,但這個類又不符合系統的接口,怎麼辦?詳細設計階段不要考慮使用適配器模式,使用主要場景爲擴展應用中。

類適配器

_Target 目標角色:_該角色定義把其餘類轉換爲什麼種接口,也就是咱們的指望接口。

_Adaptee 源角色:_你想把誰轉換成目標角色,這個「誰」就是源角色,它是已經存在的、運行良好的類或對象,通過適配器角色的包裝,它會成爲一個嶄新、靚麗的角色。

_Adapter 適配器角色:_適配器模式的核心角色,其餘兩個角色都是已經存在的角色,而適配器角色是須要新創建的,它的職責很是簡單:把源角色轉換爲目標角色,怎麼轉換?經過繼承或是類關聯的方式。

對象適配器

不使用多繼承或繼承的方式,而是使用直接關聯,或者稱爲委託的方式。

對象適配器和類適配器的區別:

類適配器是類間繼承,對象適配器是對象的合成關係,也能夠說是類的關聯關係,這是二者的根本區別。實際項目中對象適配器使用到的場景相對比較多。

代碼示例

`public class Adapter extends Target`
`{`
 `private Adaptee adaptee;`
 `public Adapter(Adaptee adaptee)`
 `{`
 `this.adaptee=adaptee;`
 `}`
 `public void request()`
 `{`
 `adaptee.specificRequest();`
 `}`
`}`

迭代器模式

概念

它提供一種方法訪問一個容器對象中各個元素,而又不需暴露該對象的內部細節。

結構

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

_ConcreteIterator 具體迭代器:_具體迭代器角色要實現迭代器接口,完成容器元素的遍歷。

_Aggregate 抽象容器:_容器角色負責提供建立具體迭代器角色的接口,必然提供一個相似createIterator()這樣的方法,在 Java 中通常是 iterator()方法。

_Concrete Aggregate 具體容器:_具體容器實現容器接口定義的方法,建立出容納迭代器的對象。

代碼示例

`/**`
 `* 具體迭代器`
 `*/`
`public class ConcreteIterator<T> implements Iterator<T> {`
 `private List<T> list = new ArrayList<>();`
 `private int cursor = 0;`
 `public boolean hasNext() {`
 `return cursor != list.size();`
 `}`
 `public T next() {`
 `T obj = null;`
 `if (this.hasNext()) {`
 `obj = this.list.get(cursor++);`
 `}`
 `return obj;`
 `}`
`}`

組合模式

概念

將對象組合成樹形結構以表示「部分-總體」的層次結構,使得用戶對單個對象和組合對象的使用具備一致性。

使用場景

  • 維護和展現部分-總體關係的場景,如樹形菜單、文件和文件夾管理。

  • 從一個總體中可以獨立出部分模塊或功能的場景。

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

結構

Component 抽象構件角色:定義參加組合對象的共有方法和屬性,能夠定義一些默認的行爲或屬性。

_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;`
 `}` 
`}`

觀察者模式

概念

定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則全部依賴於它的對象都會獲得通知並被自動更新。

使用場景

  • 關聯行爲場景。須要注意的是,關聯行爲是可拆分的,而不是「組合」關係。

  • 事件多級觸發場景。

  • 跨系統的消息交換場景,如消息隊列的處理機制。

結構

_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();`
 `}`
 `}` 
`}`

門面模式

概念

要求一個子系統的外部與其內部的通訊必須經過一個統一的對象進行。門面模式提供一個高層次的接口,使得子系統更易於使用。

使用場景

  • 爲一個複雜的模塊或子系統提供一個供外界訪問的接口

  • 子系統相對獨立——外界對子系統的訪問只要黑箱操做便可

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

結構

_Facade 門面角色:_客戶端能夠調用這個角色的方法。此角色知曉子系統的全部功能和責任。通常狀況下,本角色會將全部從客戶端發來的請求委派到相應的子系統去,也就說該角色沒有實際的業務邏輯,只是一個委託類。

_subsystem 子系統角色:_能夠同時有一個或者多個子系統。每個子系統都不是一個單獨的類,而是一個類的集合。子系統並不知道門面的存在。對於子系統而言,門面僅僅是另一個客戶端而已。

代碼模式

`public class Client {`
 `//委託的子系統對象`
 `private A a= new A();`
 `private B b= new B();`
 `private C c= new C();`
 `//提供外部訪問的方法`
 `public void methodA(){`
 `this.a.doSomething();`
 `}`
 `public void methodB(){`
 `this.b.doSomething();`
 `}`
 `public void methodC(){`
 `this.c.doSomething();`
 `}`
`}`

備忘錄模式

概念

在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。這樣之後就可將該對象恢復到原先保存的狀態。

使用場景

  • 須要保存和恢復數據的相關狀態場景。

  • 提供一個可回滾(rollback)的操做。

  • 須要監控的副本場景中。

  • 數據庫鏈接的事務管理就是用的備忘錄模式。

結構

_Originator 發起人角色:_記錄當前時刻的內部狀態,負責定義哪些屬於備份範圍的狀態,負責建立和恢復備忘錄數據。

_Memento 備忘錄角色:_負責存儲 Originator 發起人對象的內部狀態,在須要的時候提供發起人須要的內部狀態。

_Caretaker 備忘錄管理員角色:_對備忘錄進行管理、保存和提供備忘錄。

代碼示例

`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();`
 `}`
 `}`
`}`

訪問者模式

概念

封裝一些做用於某種數據結構中的各元素的操做,它能夠在不改變數據結構的前提下定義做用於這些元素的新的操做。

使用場景

  • 一個對象結構包含不少類對象,它們有不一樣的接口,而你想對這些對象實施一些依賴於其具體類的操做,也就說是用迭代器模式已經不能勝任的情景。

  • 須要對一個對象結構中的對象進行不少不一樣而且不相關的操做,而你想避免讓這些操做「污染」這些對象的類。

結構

_Visitor——抽象訪問者:_抽象類或者接口,聲明訪問者能夠訪問哪些元素,具體到程序中就是 visit 方法的參數定義哪些對象是能夠被訪問的。

_ConcreteVisitor——具體訪問者:_它影響訪問者訪問到一個類後該怎麼幹,要作什麼事情。

_Element——抽象元素:_接口或者抽象類,聲明接受哪一類訪問者訪問,程序上是經過 accept 方法中的參數來定義的。

_ConcreteElement——具體元素:_實現 accept 方法,一般是 visitor.visit(this),基本上都造成了一種模式了。

_ObjectStruture——結構對象:_元素產生者,通常容納在多個不一樣類、不一樣接口的容器,如 List、Set、Map 等,在項目中,通常不多抽象出這個角色。

代碼示例

`public class CompensationVisitor implements Visitor {`
 `@Override`
 `public void Visit(Element element) {`
 `// TODO Auto-generated method stub`
 `Employee employee = ((Employee) element);`
 `System.out.println(`
 `employee.getName() + "'s Compensation is " + (employee.getDegree() * employee.getVacationDays() * 10));`
 `}`
`}`

狀態模式

概念

當一個對象內在狀態改變時容許其改變行爲,這個對象看起來像改變了其類。

使用場景

  • 行爲隨狀態改變而改變的場景,這也是狀態模式的根本出發點,例如權限設計,人員的狀態不一樣即便執行相同的行爲結果也會不一樣,在這種狀況下須要考慮使用狀態模式。

  • 條件、分支判斷語句的替代者

結構

_State——抽象狀態角色:_接口或抽象類,負責對象狀態定義,而且封裝環境角色以實現狀態切換。

_ConcreteState——具體狀態角色:_每個具體狀態必須完成兩個職責:本狀態的行爲管理以及趨向狀態處理,通俗地說,就是本狀態下要作的事情,以及本狀態如何過渡到其餘狀態。

_Context——環境角色:_定義客戶端須要的接口,而且負責具體狀態的切換。

代碼示例

`//抽象狀態角色`
`public abstract class State {`
 `//定義一個環境角色,提供子類訪問`
 `protected Context context;`
 `//設置環境角色`
 `public void setContext(Context _context){`
 `this.context = _context;`
 `}`
 `//行爲1`
 `public abstract void handle1();`
 `//行爲2`
 `public abstract void handle2();`
`}`

解釋器模式

概念

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

使用場景

  • 重複發生的問題可使用解釋器模式

  • 一個簡單語法須要解釋的場景

結構

_AbstractExpression——抽象解釋器:_具體的解釋任務由各個實現類完成,具體的解釋器分別由TerminalExpression 和 Non-terminalExpression 完成。

_TerminalExpression——終結符表達式:_實現與文法中的元素相關聯的解釋操做,一般一個解釋器模式中只有一個終結符表達式,但有多個實例,對應不一樣的終結符。

_NonterminalExpression——非終結符表達式:_文法中的每條規則對應於一個非終結表達式,非終結符表達式根據邏輯的複雜程度而增長,原則上每一個文法規則都對應一個非終結符表達式。

_Context——環境角色:_通常是用來存放文法中各個終結符所對應的具體值,這些信息須要存放到環境角色中,不少狀況下咱們使用 Map 來充當環境角色就足夠了。

代碼示例

`/**`
 `* 終結符表達式`
 `*/`
`public class TerminalExpression extends AbstractExpression {`
 `@Override`
 `public void interpret(Context ctx) {`
 `// 實現與語法規則中的終結符相關聯的解釋操做`
 `}`
`}`
`/**`
 `* 非終結符表達式`
 `*/`
`public class NonterminalExpression extends AbstractExpression {`
 `@Override`
 `public void interpret(Context ctx) {`
 `// 實現與語法規則中的非終結符相關聯的解釋操做`
 `}`
`}`

享元模式

概念

使用共享對象可有效地支持大量的細粒度的對象。

對象的信息分爲兩個部分:內部狀態(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;`
 `}`
`}`

橋樑模式

概念

抽象和實現解耦,使得二者能夠獨立地變化。

使用場景

  • 不但願或不適用使用繼承的場景

  • 接口或抽象類不穩定的場景

  • 重用性要求較高的場景

結構

_Abstraction——抽象化角色:_它的主要職責是定義出該角色的行爲,同時保存一個對實現化角色的引用,該角色通常是抽象類。

_Implementor——實現化角色:_它是接口或者抽象類,定義角色必需的行爲和屬性。

_RefinedAbstraction——修正抽象化角色:_它引用實現化角色對抽象化角色進行修正。

_ConcreteImplementor——具體實現化角色:_它實現接口或抽象類定義的方法和屬性。

代碼示例

`public abstract class Abstraction {`
 `//定義對實現化角色的引用`
 `private Implementor imp;`
 `//約束子類必須實現該構造函數`
 `public Abstraction(Implementor _imp){`
 `this.imp = _imp;`
 `}`
 `//自身的行爲和屬性`
 `public void request(){`
 `this.imp.doSomething();`
 `}`
 `//得到實現化角色`
 `public Implementor getImp(){`
 `return imp;`
 `}`
`}`

總結

你們在學習設計模式的時候,不要把它看得有多難,歸根結底,都是一些概論性的總結。須要咱們在平時的不斷學習和工做中,慢慢去理解它的深層原理,這樣才能靈活應用每一種設計模式。

設計模式是在前人的總結上,對一些場景的問題的進行解決的一種方案,設計模式不是公式,不必去死記硬背每一種模式,更重要的是瞭解它的抽象思想,以及應用設計模式怎麼更好的解決問題,能夠達成什麼效果。理論雖多,可是咱們要把它掌握的話,對於咱們的實際開發來講會解決很多的問題。

固然後面還會繼續爲你們更新關於設計原則的內容,方便你們進一步理解設計模式。

相關文章
相關標籤/搜索