外觀模式 | Facade Pattern

Posted by Ian Tsai on Saturday, September 26, 2020

本系列文章同步分享於IT邦幫忙第12屆鐵人賽


Design Pattern 系列文章導讀


Design Pattern可以說是開發上大家都會遇到的一個課題, 這系列文會從Design Principles、各種design pattern到最後的Anti-Patterns & Code Smells介紹下去,讓我們可以更了解各種pattern的使用時機與場合。 預計目標主題如下,若有哪部分不熟的章節可以直接點進去看
註:可以利用Online Java Compiler IDE

  1. 設計模式 - 入門篇
  2. 設計模式 - 原則篇 | Design Principles
  3. 設計模式 - 創建型模型篇 | Creational Patterns
  4. 設計模式 - 結構型模型篇 | Structural Patterns
  5. 設計模式 - 行為型模型篇 | Behavioural Patterns
  6. 設計模式 - 番外篇
  • 定義


為子系統中的一組接口提供一個統一的高層接口,使得子系統更容易使用。

簡單來說,就是提供一個接口給客戶端使用,接口內包含眾多子系統的功能。比方說,當要找銀行貸款時,我們只需要找專員,而專員把我們的資料拿到後,要回銀行各部門跑流程,最後才能核貸給我們。行員就是接口,銀行各部門就是子系統。

  • Facade Pattern 成員


成員 功用
Facade 為多個SubSystem對外提供的一個接口。
SubSystem 系統各種不同的功能,Client透過Facade使用。

拿剛剛講的貸款的例子,銀行行員就是Facade的接口。而他裡面的SubSystem就是去各部門跑流程,為了完成客戶的貸款。

  • Facade Pattern 實作


首先我們先將銀行各部門的系統給建立起來(由於本人不清楚貸款要跑哪些部門,所以用ABCD代替)

class Department_A {
    public void method1() {
        System.out.println("Data sent to the departmentA");
    }   
}
class Department_B {
    public  void method2() {
        System.out.println("Data sent to the departmentB");
    }   
}
class Department_C {
    public  void method3() {
        System.out.println("Data sent to the departmentC");
    }   
}
class Department_D {
    public  void method4() {
        System.out.println("Data sent to the departmentD");
    }   
}

我們建立了ABCD四個子系統。現在需要一個Facade來把所有的子系統包裝起來:

class CommissionerFacade {
    private Department_A obj1 = new Department_A();
    private Department_B obj2 = new Department_B();
    private Department_C obj3 = new Department_C();
    private Department_D obj4 = new Department_D();
    public void method() {
        obj1.method1();
        obj2.method2();
        obj3.method3();
        obj4.method4();
    }
}

銀行專員就是Facade,將所有的子系統包裝在method()內,也就是說,由他去找各部門辦事情,Client不需要管。

最後Client將Facade建立起來並呼叫裡面的method(),來完成我們貸款的行為。

public class PCHome {
    public static void main(String[] args) {
        CommissionerFacade f = new CommissionerFacade();
        f.method();
    }
}

output

Data sent to the departmentA
Data sent to the departmentB
Data sent to the departmentC
Data sent to the departmentD

這就是Facade Pattern實作後的程式碼。UML可以看出,由專員處理一切事務,我們只需要對應專員即可,不需要知道銀行各部門到底在幹嘛。這看起來很簡單,但如果沒使用的話會長怎樣呢?

public class Bank {
    public static void main(String[] args) {
        Department_A obj1 = new Department_A();
        Department_B obj2 = new Department_B();
        Department_C obj3 = new Department_C();
        Department_D obj4 = new Department_D();
        obj1.method1();
        obj2.method2();
        obj3.method3();
        obj4.method4();
}

如果沒有Facade,就像沒了專員,若要貸款就要自己去銀行各部門跑流程。這樣Client會直接相依到子系統,這樣若未來子系統需要做更動,可能會影響到Client端。這樣就違反了開閉原則。

  • 小結


Facade Pattern的目標

為子系統中的一組接口提供一個統一的高層接口,使得子系統更容易使用。

Facade Pattern的成員
Facade:統一的入口,如銀行專員。
SubSystem:各種系統,如銀行各部門。
Facade Pattern的優缺點
優點
1. Client對只對Facade有關,與SubSystem無關,此模式迪米特法則的典型應用。
2. 降低SubSystem與Client間的耦合度,未來子系統若需要更新不需要異動到其他程式碼。
缺點
1. 無法限制Client使用SubSystem。
2. 增加新的SubSystem可能會需要修改Facade,違反OCP。
Facade Pattern的使用時機
1. 為複雜的模組或子系統提供給外面呼叫的模組。 
2. 子系統相對獨立。
  • 範例程式碼


範例:實作Facade Pattern

  • References


  • 外观模式(Facade模式)详解
  • 外观模式