意圖(Intent)#

為子系統中的一組介面提供一個統一的高層介面。Facade 定義了一個更容易使用的介面,簡化子系統的使用。

動機(Motivation)#

將系統結構化為子系統有助於降低複雜度。一個常見的設計目標是最小化子系統之間的溝通和依賴。達成這個目標的方式之一,就是引入一個 facade 物件,為子系統的一般性功能提供單一、簡化的介面。

以一個編譯器子系統為例,它包含 ScannerParserProgramNodeBytecodeStreamProgramNodeBuilder 等類別。大多數客戶端只想編譯程式碼,不關心解析和程式碼生成的細節。這些低階介面只會增加他們的使用負擔。

解決方案是提供一個 Compiler 類別作為 facade——它提供編譯功能的單一簡化介面,將底層類別黏合在一起,但不完全隱藏它們。對大多數程式設計師而言,facade 讓生活更簡單;而少數需要更多控制的人仍然可以直接使用底層類別。

Facade 不是為了阻止客戶端使用子系統類別,而是提供一條簡單的捷徑。客戶端可以在「便利性」和「完整控制」之間自由選擇。

適用場景(Applicability)#

  • 想為複雜子系統提供簡單介面。隨著演化,子系統往往變得更複雜,Facade 為大多數客戶端提供足夠好的預設視圖
  • 客戶端與子系統實作之間存在大量依賴。引入 Facade 解耦子系統,提升子系統的獨立性和可攜性
  • 想將子系統分層。使用 Facade 為每個子系統層級定義進入點,讓子系統之間僅透過 facade 溝通

結構(Structure)#

Facade 知道哪些子系統類別負責處理哪些請求,將客戶端請求委派給適當的子系統物件。子系統類別不知道 Facade 的存在。

classDiagram
    class Facade {
        +Operation()
    }
    class SubsystemClassA {
        +OperationA()
    }
    class SubsystemClassB {
        +OperationB()
    }
    class SubsystemClassC {
        +OperationC()
    }
    Facade --> SubsystemClassA
    Facade --> SubsystemClassB
    Facade --> SubsystemClassC
    Client --> Facade

參與者(Participants)#

參與者範例職責
FacadeCompiler知道哪些子系統類別負責處理請求;將客戶端請求委派給適當的子系統物件
Subsystem classesScanner、Parser、ProgramNode 等實作子系統功能;處理 Facade 指派的工作;不持有對 Facade 的引用,不知道它的存在

協作方式(Collaborations)#

  • 客戶端透過 Facade 發送請求,Facade 轉發給適當的子系統物件。子系統物件執行實際工作,Facade 可能需要做自己的轉換工作
  • 使用 Facade 的客戶端不需要直接存取子系統物件

優缺點(Consequences)#

  • 減少客戶端面對的物件數量:遮蔽子系統元件,使子系統更容易使用
  • 促進弱耦合:子系統與客戶端之間的弱耦合讓子系統元件可以自由變化而不影響客戶端。Facade 有助於系統分層和消除複雜或循環依賴。在大型系統中,減少編譯依賴可以大幅節省重新編譯的時間
  • 不阻止直接使用子系統:客戶端可以選擇使用 Facade 的便利介面,或直接使用子系統類別以獲得完整功能

實作要點(Implementation)#

  • 降低客戶端-子系統耦合
    • 將 Facade 定義為抽象類別,不同子系統實作對應不同的具體子類別
    • 或用不同的子系統物件來配置 Facade,替換子系統物件即可客製化行為
  • 子系統類別的公私分離
    • 子系統的「公開介面」包含所有客戶端可存取的類別(Facade 是其中之一,但不是唯一)
    • 子系統的「私有介面」只供子系統擴展者使用
    • C++ 可用 namespace 來控制子系統類別的可見性

Facade 通常只需要一個實例,因此常實作為 Singleton。但這不是硬性規定——設計時應根據實際需求決定。

已知應用(Known Uses)#

  • ObjectWorks\Smalltalk 編譯器:Compiler 類別作為 Scanner、Parser 等編譯子系統的 facade
  • ET++:ProgrammingEnvironment facade 提供 InspectObject、InspectClass 等操作,遮蔽底層的瀏覽工具子系統。應用程式不需知道瀏覽環境是否可用(抽象耦合)
  • Choices 作業系統:使用 facade 將多個 framework 組合為一。FileSystemInterface(儲存)和 Domain(位址空間)分別作為對應子系統的代表(facade)

相關模式(Related Patterns)#

  • Abstract Factory:可與 Facade 搭配使用,提供子系統物件的建立介面,避免平台相關的類別暴露
  • Mediator:與 Facade 類似,都抽象化了既有類別的功能。但 Mediator 抽象的是同事物件之間的任意通訊,同事物件知道 Mediator 的存在;Facade 只是簡化子系統的介面,子系統類別不知道 Facade 的存在
  • Singleton:Facade 物件通常只需一個,因此常是 Singleton