---
# System prepended metadata

title: Facade 外觀、門面模式
tags: [基礎進階, Java 設計模式]

---

---
title: 'Facade 外觀、門面模式'
disqus: kyleAlien
---

Facade 外觀、門面模式
===

## Overview of Content

:::success
* 如果喜歡讀更好看一點的網頁版本，可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/)
    
    本篇文章對應的是 [**Facade 外觀、門面模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_facade/)
:::

[TOC]

## Facade 使用場景
>  **也稱為`門面模式`，外部與內部的通信必須通過一個統一的對象進行**，簡單來說就是一個封裝功能給使用者使用，而使用者不必知道內部細節

* 讓 User 使用系統時不必親自做細節通信 (也不依賴過多類)，而是訪問透過外觀類就可使用，**可當作==一層隔離==**
    
    > 其實 [**Adapter 適配器模式**](https://hackmd.io/@AlienHackMd/BJ_NojcvU) 就屬於一種小型的外觀模式，不過他更針對指定介面去小規模適配

* 當維護一個遺留的大型系統時，新的類又必須依賴它就可使用外觀模式，外觀模式做仲介；而外觀通常會透過單例模式來訪問，他們對子系統的實現提供了「防變異」、「低耦合的好處」（`GRASP`）

    此時外觀用用來隔離新系統訪問舊系統的規則，新系統不會直接觸碰到舊系統，概念程式如下

    ```kotlin=
    class NewSystem {
        
        fun doSomething() {
            
            if(!Facade.openGate(this)) {
                return
            }
            
            ...
        }
        
    }
    
    
    // 外觀包裝舊系統 ------------------------------------------
    object Facade {
        
        private val oldSystem: OldSystem
        
        fun openGate(newSystem: NewSystem): Boolean {
             oldSystem.foo()   
        }

    }


    class OldSystem {
        
        fun foo() {
            ...
        }
        
    }
    ```


### Facade 定義 & UML

* **Facade 定義**：提供提供一個統一界面隔離使用者與子系統 (sub system) 直接的互交，讓使用者使用起來更方便

* Facade UML 角色介紹

    | Facade 角色 | 說明 |
    | - | - |
    | Facade | 對外使用的窗口，內部持有一個 SubSystem 對象，所有的實做交由 SubSystem 處理 |
    | SubSystem | 子系統可以有 1 ～ 多個，每個子系統都是單獨的類 |

    > ![](https://i.imgur.com/VozQemn.png)


### Facade 設計 - 優缺點

* Facade 設計**優點** : 
    
    1. 減少子類的依賴，所有細節在外觀類實作，與子類無關
    
        > 解開強耦合：避免外界訪問直接侵入到子系統中
    
    2. 對用戶隱藏細節實現，減少用戶對子系統的依賴以及使用，即使子類產生變化，只需修改外觀類即可

        > 符合了高內據的特性
    
    3. 加強了安全性，如果外觀類並無實現功能時，使用者也無法調度子系統

* Facade 設計**缺點** : 
    
    **不符合開閉原則**，因為需求一做更改勢必會修改此 (`Exterior`) 類別

### Facade 設計 - 注意事項

* 一個子系統可以有多個門面：

    假設一個子系統有許多功能，那相對的門面就會有多個方法，當方法多到一個程度就會難以管理；這時可以 **++依照功能++ 拆分多個門面**

* 門面系統 **可以限制使用者的使用**


    ```kotlin=
    class Facade {

        private val subSys = SubSystem()

        fun working() {
            // classA 是不限制
            subSys.classA.work()
        }

        fun workingWithLimit() {
            // classB 則有限制
            subSys.classB.work()
        }

    }
    ```
    
* **==Facde 門面不應該也不能有具體的業務邏輯==，它的則認識提供一個訪問子系統的路徑而已**，否則它會產生令一個大問題：子系統只能透過門面訪問（這是設計上的嚴重錯誤！）

    ```kotlin=
    class Facde {

        private val subSysA = WorkSystem()
        private val subSysB = DownloadSystem()

        // 該函數在門面模式上建構了邏輯！（錯誤）
        fun workingWithOrder() {
            if(subSysB.download()) {
                subSysA.work()
            }
        }
    }   
    ```
    
    正確解決方式應該是透過 **建立一個封裝類**，並讓門面持有該封裝類讓門面去使用

    ```kotlin=
    class MyRequest {
        private val subSysA = WorkSystem()
        private val subSysB = DownloadSystem()

        fun checkAndWork() {
            if(subSysB.download()) {
                subSysA.work()
            }
        }
    }
    
    
    class Facde {

        private val subSysA = WorkSystem()
        private val subSysB = DownloadSystem()
        private val subSysC = MyRequest()

        // 該函數在門面模式上建構了邏輯！（錯誤）
        fun workingWithOrder() {
            subSysC.checkAndWork()
        }
    }   
    ```

## Facade 實現

### Facade 標準

1. **`SubSystem` 類**：以下使用 2 個子系統 `Eat`、`Work`，兩個子系統個別提供不同面向的功能

    ```kotlin=
    class Eat {    // 子系統 1 
        fun eatBreakfast(): String {
            return " Breakfast"
        }

        fun eatLunch(): String {
            return " Lunch"
        }

        fun eatDinner(): String {
            return " Dinner"
        }
    }

    class Work {    // 子系統 2 
        fun monWork(): String {
            return " Coding"
        }

        fun afternoonWork(): String {
            return " Rearch"
        }

        fun nightWork(): String {
            return " Write Note"
        }
    }
    ```

2. **`Facade` 類**：內部依賴（持有）2 個子系統的實做，並透過操控兩個子系統來達到符合使用者個需求

    ```kotlin=
    class EngineerDay(name: String) {
        
        // 依賴多個子系統
        private val e: Eat = Eat()
        private val w: Work = Work()
        private val name: String

        init {
            this.name = name
        }

        // 使用子系統達成使用者需求
        fun morning() {
            println(name + e.eatBreakfast())
            println(name + w.monWork())
        }

        fun noon() {
            println(name + e.eatLunch())
            println(name + w.afternoonWork())
        }

        fun night() {
            println(name + e.eatDinner())
            println(name + w.nightWork())
        }
    }
    ```

* 使用 Facade 類範例：

    ```kotlin=
    fun main() {
        EngineerDay("Alien").run {
            morning()

            noon()

            night()
        }
    }
    ```
    > ![](https://i.imgur.com/yuWaiq4.png)

## 更多的物件導向設計

物件導向的設計基礎如下，如果是初學者或是不熟悉的各位，建議可以從這些基礎開始認識，打好基底才能走個更穩（在學習的時候也需要不斷回頭看）！

:::info
* [**設計建模 2 大概念- UML 分類、使用**](https://devtechascendancy.com/introduction-to-uml-and-diagrams/)

* [**物件導向設計原則 – 6 大原則(一)**](https://devtechascendancy.com/object-oriented-design-principles_1/)

* [**物件導向設計原則 – 6 大原則(二)**](https://devtechascendancy.com/object-oriented-design-principles_2/)
:::


### 創建模式 - Creation Patterns

* [**創建模式 PK**](https://devtechascendancy.com/pk-design-patterns-factory-builder-best/)

* **創建模式 - `Creation Patterns`**：
    
    創建模式用於「**物件的創建**」，它關注於如何更靈活、更有效地創建對象。這些模式可以隱藏創建對象的細節，並提供創建對象的機制，例如單例模式、工廠模式… 等等，詳細解說請點擊以下連結

    :::success
    
    * [**Singleton 單例模式 | 解說實現 | Android Framework Context Service**](https://devtechascendancy.com/object-oriented_design_singleton/)

    * [**Abstract Factory 設計模式 | 實現解說 | Android MediaPlayer**](https://devtechascendancy.com/object-oriented_design_abstract-factory/)

    * [**Factory 工廠方法模式 | 解說實現 | Java 集合設計**](https://devtechascendancy.com/object-oriented_design_factory_framework/)

    * [**Builder 建構者模式 | 實現與解說 | Android Framwrok Dialog 視窗**](https://devtechascendancy.com/object-oriented_design_builder_dialog/)
    
    * [**Clone 原型模式 | 解說實現 | Android Framework Intent**](https://devtechascendancy.com/object-oriented_design_clone_framework/)

    * [**Object Pool 設計模式 | 實現與解說 | 利用 JVM**](https://devtechascendancy.com/object-oriented_design_object-pool/)

    * [**Flyweight 享元模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_flyweight/)
    :::


### 行為模式 - Behavioral Patterns

* [**行為模式 PK**](https://devtechascendancy.com/pk-design-patterns-cmd-strat-state-obs-chain/)

* **行為模式 - `Behavioral Patterns`**：
    
    行為模式關注物件之間的「**通信**」和「**職責分配**」。它們描述了一系列對象如何協作，以完成特定任務。這些模式專注於改進物件之間的通信，從而提高系統的靈活性。例如，策略模式、觀察者模式… 等等，詳細解說請點擊以下連結

    :::warning
    * [**Stragety 策略模式 | 解說實現 | Android Framework 動畫**](https://devtechascendancy.com/object-oriented_design_stragety_framework/)

    * [**Interpreter 解譯器模式 | 解說實現 | Android Framework PackageManagerService**](https://devtechascendancy.com/object-oriented_design_interpreter_framework/)

    * [**Chain 責任鏈模式 | 解說實現 | Android Framework View 事件傳遞**](https://devtechascendancy.com/object-oriented_design_chain_framework/)

    * [**State 狀態模式 | 實現解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_state/)

    * [**Specification 規格模式 | 解說實現 | Query 語句實做**](https://devtechascendancy.com/object-oriented_design_specification-query/)

    * [**Command 命令、Servant 雇工模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_command_servant/)

    * [**Memo 備忘錄模式 | 實現與解說 | Android Framwrok Activity 保存**](https://devtechascendancy.com/object-oriented_design_memo_framework/)

    * [**Visitor 設計模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_visitor_dispatch/)

    * [**Template 設計模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_template/)

    * [**Mediator 模式設計 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_programming_mediator/)

    * [**Composite 組合模式 | 實現與解說 | 物件導向設計**](https://devtechascendancy.com/object-oriented_programming_composite/)
    :::


### 結構模式 - Structural Patterns

* [**結構模式 PK**](https://devtechascendancy.com/pk-design-patterns-proxy-decorate-adapter/)

* **結構模式 - `Structural Patterns`**：
    
    結構模式專注於「物件之間的組成」，以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時，不會破壞其整體結構。例如，外觀模式、代理模式… 等等，詳細解說請點擊以下連結

    :::danger
    * [**Bridge 橋接模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_bridge/)

    * [**Decorate 裝飾模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_decorate/)

    * [**Proxy 代理模式 | 解說實現 | 分析動態代理**](https://devtechascendancy.com/object-oriented_design_proxy_dynamic-proxy/)

    * [**Iterator 迭代設計 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_iterator/)

    * [**Facade 外觀、門面模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_facade/)

    * [**Adapter 設計模式 | 解說實現 | 物件導向設計**](https://devtechascendancy.com/object-oriented_design_adapter/)
    :::


## Appendix & FAQ
:::info

:::

###### tags: `Java 設計模式` `基礎進階`