外觀模式(Facade Pattern) - 最易懂的設計模式解析
前言
今天我來全面總結一下Android開發中最常用的設計模式 -外觀模式。
目錄

1.jpg
1. 介紹
1.1 定義
定義了一個高層、統一的介面,外部與通過這個統一的介面對子系統中的一群介面進行訪問。
通過建立一個統一的類,用來包裝子系統中一個或多個複雜的類,客戶端可以通過呼叫外觀類的方法來呼叫內部子系統中所有方法
如下圖:

1.png
給個網站的導航例子你就懂了:以前我需要在搜尋欄逐個搜尋網站地址;有了網站導航(用了外觀模式)後,就方便很多了

1.png
1.2 主要作用
- 實現客戶類與子系統類的鬆耦合
- 降低原有系統的複雜度
- 提高了客戶端使用的便捷性,使得客戶端無須關心子系統的工作細節,通過外觀角色即可呼叫相關功能。
引入外觀角色之後,使用者只需要與外觀角色互動;
使用者與子系統之間的複雜邏輯關係由外觀角色來實現
1.3 解決的問題
- 避免了系統與系統之間的高耦合度
- 使得複雜的子系統用法變得簡單
2. 模式原理
2.1 UML類圖 & 組成

1.png
2.2 例項講解
接下來我用一個例項來對建造者模式進行更深一步的介紹。
a. 例項概況
背景:小成的爺爺已經80歲了,一個人在家生活:每次都需要開啟燈、開啟電視、開啟空調;睡覺時關閉燈、關閉電視、關閉空調;
衝突:行動不方便,走過去關閉那麼多電器很麻煩,程式碼如下:
- 電器類:
//燈類 public class SubSystemA_Light { public void on(){ System.out.println("打開了燈...."); } public void off(){ System.out.println("關閉了燈...."); } } //電視類 public class SubSystemB_Television { public void on(){ System.out.println("打開了電視...."); } public void off(){ System.out.println("關閉了電視...."); } } //空調類 public class SubSystemC_Aircondition { public void on(){ System.out.println("打開了電視...."); } public void off(){ System.out.println("關閉了電視...."); } }
- 客戶端呼叫:小成爺爺使用電器情況
public class Facade Pattern{ public static void main(String[] args){ { SubSystemA_Light light = new SubSystemA_Light(); SubSystemB_Television television = new SubSystemB_Television(); SubSystemC_Aircondition aircondition = new SubSystemC_Aircondition(); //起床後開電器 System.out.prinln("起床了"); light.on(); television.on(); aircondition.on(); System.out.prinln("可以看電視了"); //睡覺時關電器 System.out.prinln("睡覺了"); light.off(); television.off(); aircondition.off(); System.out.prinln("可以睡覺了"); } }
結果
起床了 打開了燈 打開了電視 打開了空調 可以看電視了 睡覺了 關閉了燈 關閉了電視 關閉了空調 可以睡覺了
從上面可以看出,在不使用外觀模式的情況下,小成爺爺需要對每個電器都進行操作,非常不方便
客戶端與三個子系統都發送了耦合,使得客戶端程式依賴與子系統
解決方案
小成買了一個智慧傢俱控制器(外觀物件/統一介面)給他爺爺,他爺爺只需要一鍵就能開啟/關閉 燈、電視機、空調
即用外觀模式來為所有子系統設計一個統一的介面
客戶端只需要呼叫外觀類中的方法就可以了,簡化了客戶端的操作
- 電器類同上
- 外觀類:智慧遙控器
public class Facade{ SubSystemA_Light light; SubSystemB_Television television ; SubSystemC_Aircondition aircondition; //傳參 public Facade(SubSystemA_Light light,SubSystemB_Television television,SubSystemC_Aircondition aircondition){ this.light = light; this.television= television ; this.aircondition =aircondition; } //起床後一鍵開電器 public void on{ System.out.prinln("起床了"); light.on(); television.on(); aircondition.on(); } //睡覺時一鍵關電器 System.out.prinln("睡覺了"); light.off(); television.off(); aircondition.off(); } }
- 客戶端呼叫:爺爺使用智慧遙控器的時候
public class Facade Pattern{ public static void main(String[] args){ { //例項化電器類 SubSystemA_Light light = new SubSystemA_Light(); SubSystemB_Television television = new SubSystemB_Television(); SubSystemC_Aircondition aircondition = new SubSystemC_Aircondition(); //傳參 Facade facade = new Facade(light,television,aircondition); //客戶端直接與外觀物件進行互動 facade.on; System.out.prinln("可以看電視了"); facade.off; System.out.prinln("可以睡覺了");
結果
起床了 打開了燈 打開了電視 打開了空調 可以看電視了 睡覺了 關閉了燈 關閉了電視 關閉了空調 可以睡覺了
通過上述這個常見的生活例子,我相信你已經完全明白了外觀模式的原理了!!
3. 優缺點
在全面解析完後,我來分析下其優缺點:
3.1 優點
降低了客戶類與子系統類的耦合度,實現了子系統與客戶之間的鬆耦合關係
只是提供了一個訪問子系統的統一入口,並不影響使用者直接使用子系統類
減少了與子系統的關聯物件,實現了子系統與客戶之間
的鬆耦合關係,鬆耦合使得子系統的元件變化不會影響到它的客戶。
- 外觀模式對客戶遮蔽了子系統元件,從而簡化了介面,減少了客戶處理的物件數目並使子系統的使用更加簡單。
引入外觀角色之後,使用者只需要與外觀角色互動;
使用者與子系統之間的複雜邏輯關係由外觀角色來實現
- 降低原有系統的複雜度和系統中的編譯依賴性,並簡化了系統在不同平臺之間的移植過程
因為編譯一個子系統一般不需要編譯所有其他的子系統。一個子系統的修改對其他子系統沒有任何影響,而且子系統內部變化也不會影響到外觀物件。
3.2 缺點
- 在不引入抽象外觀類的情況下,增加新的子系統可能需要修改外觀類或客戶端的原始碼,違背了“開閉原則”
- 不能很好地限制客戶使用子系統類,如果對客戶訪問子系統類做太多的限制則減少了可變性和靈活性。
4. 應用場景
- 要為一個複雜的子系統對外提供一個簡單的介面
- 提供子系統的獨立性
- 客戶程式與多個子系統之間存在很大的依賴性
引入外觀類將子系統與客戶以及其他子系統解耦,可以提高子系統的獨立性和可移植性。
在層次化結構中,可以使用外觀模式定義系統中每一層的入口
層與層之間不直接產生聯絡,而通過外觀類建立聯絡,降低層之間的耦合度。
5. 與介面卡模式的區別
- 外觀模式的實現核心主要是——由外觀類去儲存各個子系統的引用,實現由一個統一的外觀類去包裝多個子系統類,然而客戶端只需要引用這個外觀類,然後由外觀類來呼叫各個子系統中的方法。
- 這樣的實現方式非常類似介面卡模式,然而外觀模式與介面卡模式不同的是:介面卡模式是將一個物件包裝起來以改變其介面,而外觀是將一群物件 ”包裝“起來以簡化其介面。它們的意圖是不一樣的,介面卡是將介面轉換為不同介面,而外觀模式是提供一個統一的介面來簡化介面。