天天看點

java設計模式——外觀模式(Facade Pattern)

       外觀模式是一種使用頻率非常高的結構型設計模式,它通過引入一個外觀角色來簡化用戶端與子系統之間的互動,為複雜的子系統調用提供一個統一的入口,降低子系統與用戶端的耦合度,且用戶端調用非常友善。

定義:外部與一個子系統的通信必須通過一個統一的外觀對象進行,為子系統中的一組接口提供一個一緻的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。外觀模式又稱為門面模式,它是一種對象結構型模式。

結構:

  • Facade(外觀角色):在用戶端可以調用它的方法,在外觀角色中可以知道相關的(一個或者多個)子系統的功能和責任; 在正常情況下,它将所有從用戶端發來的請求委派到相應的子系統去,傳遞給相應的子系統對象處理。
  • SubSystem(子系統角色):在軟體系統中可以有一個或者多個子系統角色,每一個子系統可以不是一個單獨的類,而是一個類的集合, 它實作子系統的功能;每一個子系統都可以被用戶端直接調用,或者被外觀角色調用,它處理由外觀類傳過來的請求;子系統并不知道外觀的存在, 對于子系統而言,外觀角色僅僅是另外一個用戶端而已。

UML圖:

java設計模式——外觀模式(Facade Pattern)

場景:比如咖啡廳喝咖啡,我隻需跟服務員說出自己需要什麼咖啡就可以了,接下來服務員會用咖啡杯、具體的咖啡、水制作一杯咖啡。

代碼分析: public class Mug {

    private final String  TAG =  "Mug";

    public void initMug(){

        Log. d( TAG, " 提供一個咖啡杯 ");

    }

}

public class CoffeeBrands {

    private final String  TAG =  "CoffeeBrands";

    public void blueMountainCoffee(){

        Log. d( TAG, " 藍山咖啡 ");

    }

}

public class Water {

    private final String  TAG =  "Water";

    public void initHotWater(){

        Log. d( TAG, " 初始化一杯熱水 ");

    }

}

public class Facade {

    private CoffeeBrands  coffeeBrands =  new CoffeeBrands();

    private Mug  mug =  new Mug();

    private Water  water =  new Water();

    public void makeCoffee(){

        mug.initMug();

        coffeeBrands.blueMountainCoffee();

        water.initHotWater();

    }

}

用戶端: // 呼叫服務員(擷取外觀對象)

Facade facade =  new Facade();

// 來一杯藍山咖啡

facade.makeCoffee();

優點:

  • 對客戶屏蔽子系統元件,減少了客戶處理的對象數目并使得子系統使用起來更加容易。通過引入外觀模式,客戶代碼将變得很簡單,與之關聯的對象也很少。
  • 實作了子系統與客戶之間的松耦合關系,這使得子系統的元件變化不會影響到調用它的客戶類,隻需要調整外觀類即可。
  • 降低了大型軟體系統中的編譯依賴性,并簡化了系統在不同平台之間的移植過程,因為編譯一個子系統一般不需要編譯所有其他的子系統。一個子系統的修改對其他子系統沒有任何影響,而且子系統内部變化也不會影響到外觀對象。
  • 隻是提供了一個通路子系統的統一入口,并不影響使用者直接使用子系統類。

缺點: +

  • 不能很好地限制客戶使用子系統類,如果對客戶通路子系統類做太多的限制則減少了可變性和靈活性。
  • 在不引入抽象外觀類的情況下,增加新的子系統可能需要修改外觀類或用戶端的源代碼,違背了“開閉原則”。

适用環境:

  • 當要為一個複雜子系統提供一個簡單接口時可以使用外觀模式。該接口可以滿足大多數使用者的需求,而且使用者也可以越過外觀類直接通路子系統。
  • 客戶程式與多個子系統之間存在很大的依賴性。引入外觀類将子系統與客戶以及其他子系統解耦,可以提高子系統的獨立性和可移植性。
  • 在階層化結構中,可以使用外觀模式定義系統中每一層的入口,層與層之間不直接産生聯系,而通過外觀類建立聯系,降低層之間的耦合度。

擴充:

  • 一個系統有多個外觀類 :在外觀模式中,通常隻需要一個外觀類,并且此外觀類隻有一個執行個體,換言之它是一個單例類。在很多情況下為了節約系統資源,一般将外觀類設計為單例類。當然這并不意味着在整個系統裡隻能有一個外觀類,在一個系統中可以設計多個外觀類,每個外觀類都負責和一些特定的子系統互動,向使用者提供相應的業務功能。
  • 不要試圖通過外觀類為子系統增加新行為 :不要通過繼承一個外觀類在子系統中加入新的行為,這種做法是錯誤的。外觀模式的用意是為子系統提供一個集中化和簡化的溝通管道,而不是向子系統加入新的行為,新的行為的增加應該通過修改原有子系統類或增加新的子系統類來實作,不能通過外觀類來實作。
  • 外觀模式與迪米特法則 :外觀模式創造出一個外觀對象,将用戶端所涉及的屬于一個子系統的協作夥伴的數量減到最少,使得用戶端與子系統内部的對象的互相作用被外觀對象所取代。外觀類充當了客戶類與子系統類之間的“第三者”,降低了客戶類與子系統類之間的耦合度,外觀模式就是實作代碼重構以便達到“迪米特法則”要求的一個強有力的武器。
  • 抽象外觀類的引入 :外觀模式最大的缺點在于違背了“開閉原則”,當增加新的子系統或者移除子系統時需要修改外觀類,可以通過引入抽象外觀類在一定程度上解決該問題,用戶端針對抽象外觀類進行程式設計。對于新的業務需求,不修改原有外觀類,而對應增加一個新的具體外觀類,由新的具體外觀類來關聯新的子系統對象,同時通過修改配置檔案來達到不修改源代碼并更換外觀類的目的。

繼續閱讀