設計模式學習筆記(十三):外觀模式

1 概述

1.1 引言

根據單一權責原則,軟件中將一個系統劃分爲若干個子系統有利於下降整個系統的複雜性,使客戶類與子系統之間的通訊和相互依賴關係達到最小,方法之一就是引入一個外觀角色,爲子系統的訪問提供一個簡單而單一的入口。外觀模式經過引入一個新的外觀角色來下降原有系統的複雜度,同時下降客戶類與子系統類的耦合度。java

(這裏的子系統是廣義的概念,能夠是一個類,一個功能模塊,系統的一個組成部分或者一個完整的系統)編程

若是沒有外觀角色,每一個客戶端可能須要和多個子系統之間進行復雜的交互,系統的耦合度很大,簡化示意圖以下:設計模式

設計模式學習筆記(十三):外觀模式

而引入外觀角色後,客戶端只需直接與外觀角色交互,客戶端與子系統之間的原有複雜度由外觀角色實現,從而下降系統耦合度,簡化示意圖以下:微信

設計模式學習筆記(十三):外觀模式

外觀模式要求一個子系統的外部與其內部的通訊經過一個統一的外觀角色進行,外觀角色將客戶端與子系統的內部複雜性分隔開,使得客戶端只須要與外觀角色打交道,而不須要與子系統內部的不少對象打交道。ide

1.2 定義

外觀模式:外部與一個子系統的通訊經過一個統一的外觀角色進行,爲子系統中的一組接口提供一個一致的入口。學習

外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。測試

外觀模式又叫門面模式,是一種對象結構型模式。加密

1.3 結構圖

設計模式學習筆記(十三):外觀模式

1.4 角色

  • Facade(外觀角色):在客戶端能夠調用這個角色的方法,在外觀角色中能夠知道相關的一個或多個子系統的功能和責任,正常狀況下未來自客戶端的請求委派到對應的子系統中去,傳遞給相應的子系統對象處理
  • SubSystem(子系統角色):每個子系統是一個單獨的類,也能夠是一個類的集合,實現子系統的功能。每個子系統均可以被客戶端直接調用,或者被外觀角色調用,它處理由外觀類傳過來的請求,子系統並不知道外觀類的存在,對於子系統而已,外觀角色僅僅是另外一個客戶端

2 典型實現

2.1 步驟

  • 定義子系統:首先定義子系統,實現一個單一的功能,處理由客戶端傳來的請求
  • 定義外觀角色:外觀角色能夠知道一個或多個子系統的功能和責任,未來自客戶端的請求委派到對應的子系統去,外觀角色對於子系統而言是另外一個客戶端

2.2 外觀角色

一般實現以下:設計

class Facade
{
    private SubSystemA subSystemA = new SubSystemA();
    private SubSystemB subSystemB = new SubSystemB();
    private SubSystemC subSystemC = new SubSystemC();

    public void method()
    {
        subSystemA.method();
        subSystemB.method();
        subSystemC.method();
    }
}

class SubSystemA
{
    public void method()
    {
        System.out.println("子系統A");
    }
}

class SubSystemB
{
    public void method()
    {
        System.out.println("子系統B");
    }
}

class SubSystemC
{
    public void method()
    {
        System.out.println("子系統C");
    }
}

2.3 客戶端

使用外觀模式的緣由就是簡化客戶端的調用,在這裏只需定義外觀對象並調用業務方法便可:code

Facade facade = new Facade();
facade.method();

3 實例

設計一個文件加密系統,加密流程包括三部分:讀取文件,加密文件,保存文件。這三個操做相對獨立,而且封裝在三個不一樣的類中,使用外觀模式設計該系統。

設計以下:

  • 子系統類:FileReader+Encrypt+FileWriter
  • 外觀角色類:Facade
  • FileReader:文件讀取類
  • Encrypt:文件加密類
  • FileWriter:文件保存類

代碼以下:

public class Test
{
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.fileEncrypt("111");
    }
}

class FileReader
{
    public void read(String name)
    {
        System.out.println("讀取文件"+name);
    }
}

class Encrypt
{
    public void encrypt(String name)
    {
        System.out.println("加密文件"+name);
    }
}

class FileWriter
{
    public void write(String name)
    {
        System.out.println("保存文件"+name);
    }
}

class Facade
{
    private FileReader reader = new FileReader();
    private Encrypt encrypt = new Encrypt();
    private FileWriter writer = new FileWriter();

    public void fileEncrypt(String name)
    {
        reader.read(name);
        encrypt.encrypt(name);
        writer.write(name);
    }
}

這裏的例子比較簡單,其實就是將讀取,加密以及保存操做用外觀角色包裝起來,方便客戶端調用。

4 引入抽象外觀類

4.1 爲何須要引入抽象外觀類?

在標準的外觀模式結構中,若是須要增長,刪除或修改外觀類交互的子系統類,必須修改外觀類或客戶端的源代碼,這將違背開閉原則,好比上面的例子中須要更換一種加密方法,也就是換一個加密類,這樣須要直接修改外觀類。

能夠經過引入抽象外觀類來解決該問題,引入後,客戶端能夠針對抽象外觀類進行編程,對於新的業務需求不須要修改原有的外
觀類,只須要新增一個對應的具體外觀類便可。

4.2 如何引入?

首先定義抽象外觀類,接着具體外觀類繼承或者實線抽象外觀類便可。客戶端針對抽象外觀類進行編程,在運行時再肯定具體的外觀類,好比在上面例子的基礎上修改加密方法,首先定義抽象外觀類(這裏是接口,只有一個加密方法):

interface AbstractFacade
{
    void encrypt(String name);
}

接着定義具體外觀類:

class Facade1 implements AbstractFacade
{
    private FileReader reader = new FileReader();
    private Encrypt1 encrypt1 = new Encrypt1();
    private FileWriter writer = new FileWriter();

    @Override
    public void encrypt(String name)
    {
        reader.read(name);
        encrypt1.encrypt(name);
        writer.write(name);
    }
}

class Facade2 implements AbstractFacade
{
    private FileReader reader = new FileReader();
    private Encrypt2 encrypt2 = new Encrypt2();
    private FileWriter writer = new FileWriter();

    @Override
    public void encrypt(String name)
    {
        reader.read(name);
        encrypt2.encrypt(name);
        writer.write(name);
    }
}

這兩個類除了加密方法不同其餘都同樣,測試:

AbstractFacade facade = new Facade1();
facade.encrypt("111");
facade = new Facade2();
facade.encrypt("222");

引入抽象外觀類後,客戶端針對抽象外觀類進行編程,運行時肯定具體外觀類,輸出以下:
設計模式學習筆記(十三):外觀模式

5 注意事項

  • 外觀單例:不少狀況下爲了節約系統資源,系統只須要一個外觀類的實例,也就是外觀類能夠是一個單例類,這樣能夠下降系統資源的消耗
  • 多個外觀類:在一個系統中能夠設計多個外觀類,每一個外觀類負責和一些特定子對象交互,向客戶端提供相應業務功能
  • 不要經過外觀類增長新行爲:外觀模式的意圖是爲子系統提供一個集中簡化的溝通渠道,而不是向子系統中增長新行爲,新行爲的增長應該經過修改原有子系統類或增長新的子系統類來實現而不是經過外觀類實現

6 主要優勢

  • 簡化處理:對客戶端屏蔽了子系統組件,減小了客戶端所需處理的對象數目並使得子系統使用起來更加容易,引入外觀模式後客戶端代碼將簡化
  • 鬆耦合:實現了子系統於客戶端之間鬆耦合關係,使得子系統的變化不會影響到客戶端,只需修改外觀類
  • 子系統修改靈活:一個子系統的修改對其餘子系統沒有影響,並且子系統內部變化也不會影響外觀對象
  • 惟一入口:只提供了一個訪問子系統的惟一入口,但不會影響客戶端直接使用子系統類

7 主要缺點

  • 不能限制客戶端使用子系統:外觀模式不能很好地限制客戶端直接使用子系統,若是客戶端對訪問子系統作太多的限制就會減小可變性與靈活性
  • 可能須要修改外觀類:若是設計不當,增長新的子系統可能須要外觀類,違背OCP

8 適用場景

  • 當要爲訪問一系列複雜的子系統提供一個簡單的入口時
  • 客戶端與多個子系統存在很大依賴性
  • 層次化結構中,能夠使用外觀模式定義系統中每一層的入口,層與層之間不直接產生聯繫,而經過外觀類創建聯繫,下降層之間的耦合度

9 總結

設計模式學習筆記(十三):外觀模式

若是以爲文章好看,歡迎點贊。

同時歡迎關注微信公衆號:氷泠之路。

在這裏插入圖片描述

相關文章
相關標籤/搜索