設計模式(十五)----結構型模式之外觀模式

2023-03-05 06:02:47

1 概述

有些人可能炒過股票,但其實大部分人都不太懂,這種沒有足夠了解證券知識的情況下做股票是很容易虧錢的,剛開始炒股肯定都會想,如果有個懂行的幫幫手就好,其實基金就是個好幫手,支付寶裡就有許多的基金,它將投資者分散的資金集中起來,交由專業的經理人進行管理,投資於股票、債券、外匯等領域,而基金投資的收益歸持有者所有,管理機構收取一定比例的託管管理費用。

定義:

又名門面模式,是一種通過為多個複雜的子系統提供一個一致的介面,而使這些子系統更加容易被存取的模式。該模式對外有一個統一介面,外部應用程式不用關心內部子系統的具體的細節,這樣會大大降低應用程式的複雜度,提高了程式的可維護性。

外觀(Facade)模式是「迪米特法則」的典型應用

2 結構

外觀(Facade)模式包含以下主要角色:

  • 外觀(Facade)角色:為多個子系統對外提供一個共同的介面。

  • 子系統(Sub System)角色:實現系統的部分功能,客戶可以通過外觀角色存取它。

3 案例

【例】智慧家電控制

小明的爺爺已經60歲了,一個人在家生活:每次都需要開啟燈、開啟電視、開啟空調;睡覺時關閉燈、關閉電視、關閉空調;操作起來都比較麻煩。所以小明給爺爺買了智慧音箱,可以通過語音直接控制這些智慧家電的開啟和關閉。類圖如下:

程式碼如下:

//燈類
public class Light {
    public void on() {
        System.out.println("開啟了燈....");
    }
​
    public void off() {
        System.out.println("關閉了燈....");
    }
}
​
//電視類
public class TV {
    public void on() {
        System.out.println("開啟了電視....");
    }
​
    public void off() {
        System.out.println("關閉了電視....");
    }
}
​
//控制類
public class AirCondition {
    public void on() {
        System.out.println("開啟了空調....");
    }
​
    public void off() {
        System.out.println("關閉了空調....");
    }
}
​
//智慧音箱
public class SmartAppliancesFacade {
​
    private Light light;
    private TV tv;
    private AirCondition airCondition;
​
    public SmartAppliancesFacade() {
        light = new Light();
        tv = new TV();
        airCondition = new AirCondition();
    }
​
    public void say(String message) {
        if(message.contains("開啟")) {
            on();
        } else if(message.contains("關閉")) {
            off();
        } else {
            System.out.println("我還聽不懂你說的!!!");
        }
    }
​
    //起床後一鍵開電器
    private void on() {
        System.out.println("起床了");
        light.on();
        tv.on();
        airCondition.on();
    }
​
    //睡覺一鍵關電器
    private void off() {
        System.out.println("睡覺了");
        light.off();
        tv.off();
        airCondition.off();
    }
}
​
//測試類
public class Client {
    public static void main(String[] args) {
        //建立外觀物件
        SmartAppliancesFacade facade = new SmartAppliancesFacade();
        //使用者端直接與外觀物件進行互動
        facade.say("開啟家電");
        facade.say("關閉家電");
    }
}

好處:

  • 降低了子系統與使用者端之間的耦合度,使得子系統的變化不會影響呼叫它的客戶類。

  • 對客戶遮蔽了子系統元件,減少了客戶處理的物件數目,並使得子系統使用起來更加容易。

缺點:

  • 不符合開閉原則,修改很麻煩

4 使用場景

  • 對分層結構系統構建時,使用外觀模式定義子系統中每層的入口點可以簡化子系統之間的依賴關係。

  • 當一個複雜系統的子系統很多時,外觀模式可以為系統設計一個簡單的介面供外界存取。

  • 當用戶端與多個子系統之間存在很大的聯絡時,引入外觀模式可將它們分離,從而提高子系統的獨立性和可移植性。

5 原始碼解析

使用tomcat作為web容器時,接收瀏覽器傳送過來的請求,tomcat會將請求資訊封裝成ServletRequest物件,如下圖①處物件。但是大家想想ServletRequest是一個介面,它還有一個子介面HttpServletRequest,而我們知道該request物件肯定是一個HttpServletRequest物件的子實現類物件,到底是哪個類的物件呢?可以通過輸出request物件,我們就會發現是一個名為RequestFacade的類的物件。

RequestFacade類就使用了外觀模式。先看結構圖:

為什麼在此處使用外觀模式呢?

定義 RequestFacade 類,分別實現 ServletRequest ,同時定義私有成員變數 Request ,並且方法的實現呼叫 Request 的實現。然後,將 RequestFacade上轉為 ServletRequest 傳給 servlet 的 service 方法,這樣即使在 servlet 中被下轉為 RequestFacade ,也不能存取私有成員變數物件中的方法。既用了 Request ,又能防止其中方法被不合理的存取。