外觀模式 - Facade Patterns

定義

外觀模式提供一個統一的接口,用來訪問子系統中的一羣接口。外觀定義了一個高層接口,讓子系統更容易訪問。編程

封裝交互,簡化調用緩存

問題

假設必須在代碼中使用某個複雜的庫或框架中的衆多對象。正常狀況下,須要負責全部對象的初始化工做、管理其依賴關係並按正確的順序執行方法等。bash

最終,程序中類的業務邏輯將與第三方類的實現細節緊密耦合,使得理解和維護代碼的工做很難進行。框架

解決方案

外觀類爲包含許多活動部分的複雜子系統提供一個簡單的接口。與直接調用子系統相比,外觀提供的功能可能比較有效,但卻包含了客戶端真正關心的功能。ide

若是程序須要與包含幾十種功能的複雜庫整合,但只須要使用其中部分功能,那麼使用外觀模式會比較方便。網站

例如,上傳貓咪搞笑短視頻到社交媒體網站的應用可能會用到專業的視頻轉換庫,但它只需使用一個包含 encode(filename, format) 方法(以文件名與文件格式爲參數進行編碼的方法)的類便可。在建立這個類並將其鏈接到視頻轉換庫後,一個外觀模式就完成了。ui

案例

電話購物

當經過電話給商店下達訂單時,接線員就是該商店的全部服務和部門的外觀。接線員提供了一個同購物系統、支付網關和各類送貨服務進行互動的簡單語音接口。編碼

結構

  1. 外觀(Facade)提供了一種訪問特定子系統功能的便捷方式,其瞭解如何重定向客戶端請求,知曉如何操做一切活動部件。spa

  2. 複雜子系統(Complex Subsystem)由數十個不一樣對象構成。若是要用這些對象完成有意義的工做,你必須深刻了解子系統的實現細節,好比按照正確順序初始化對象和爲其提供正確格式的數據。設計

    子系統類不會意識到外觀的存在,它們在系統內運做而且相互之間可直接進行交互。

  3. 客戶端(Client)使用外觀代替對子系統對象的直接調用。

示例

建立一個封裝所需功能並隱藏其餘代碼的外觀類,從而無需使所有代碼直接與數十個框架類進行交互。該結構還能將將來框架升級或更換所形成的影響最小化,由於你只需修改程序中外觀方法的實現便可。

// 這裏有複雜第三方視頻轉換框架中的一些類。咱們不知曉其中的代碼,所以沒法
// 對其進行簡化。

class VideoFile
// ...

class OggCompressionCodec
// ...

class MPEG4CompressionCodec
// ...

class CodecFactory
// ...

class BitrateReader
// ...

class AudioMixer
// ...


// 爲了將框架的複雜性隱藏在一個簡單接口背後,咱們建立了一個外觀類。它是在
// 功能性和簡潔性之間作出的權衡。
class VideoConverter is
    method convert(filename, format):File is
        file = new VideoFile(filename)
        sourceCodec = new CodecFactory.extract(file)
        if (format == "mp4")
            destinationCodec = new MPEG4CompressionCodec()
        else
            destinationCodec = new OggCompressionCodec()
        buffer = BitrateReader.read(filename, sourceCodec)
        result = BitrateReader.convert(buffer, destinationCodec)
        result = (new AudioMixer()).fix(result)
        return new File(result)

// 應用程序的類並不依賴於複雜框架中成千上萬的類。一樣,若是你決定更換框架,
// 那隻需重寫外觀類便可。
class Application is
    method main() is
        convertor = new VideoConverter()
        mp4 = convertor.convert("funny-cats-video.ogg", "mp4")
        mp4.save()
複製代碼

適用範圍

  • 爲複雜子系統提供一個簡單接口。知足大多數需求的同時,也能夠越過外觀類直接訪問子系統。
  • 客戶程序與複雜子系統間存在很大依賴性。外觀類可將客戶與子系統解耦,提升子系統的獨立性和可移植性。
  • 層次化結構中,使用外觀模式定義每一層入口,層與層間經過外觀類創建聯繫,下降層之間的耦合度。

優缺點

優勢:

  1. 將客戶與複雜子系統解耦。提升子系統的獨立性和可移植性。
  2. 減小客戶端調用代碼,使子系統更容易使用。
  3. 只提供了一個新的統一入口,不影響直接調用子系統類。

缺點:

  1. 不能很好限制客戶使用子系統類,若是對客戶訪問子系統類作太多的限制則減小了可變性和靈活性。
  2. 不引入抽象外觀類的狀況下,增長新的子系統可能須要修改外觀類或客戶端的源代碼,違背了「開閉原則」

與其餘模式關係

  • 適配器模式意圖是將接口轉換成不一樣的接口,外觀模式的意圖簡化接口。
  • 當只需對客戶端代碼隱藏子系統建立對象的方式時,可使用抽象工廠模式來代替。
  • 享元模式展現瞭如何生成大量的小型對象,外觀模式則展現瞭如何用一個對象來表明整個子系統。
  • 外觀模式中介者模式的職責相似:它們都嘗試在大量緊密耦合的類中組織起合做。
    • 外觀爲子系統中的全部對象定義了一個簡單接口,可是它不提供任何新功能。子系統自己不會意識到外觀的存在。子系統中的對象能夠直接進行交流。
    • 中介者將系統中組件的溝通行爲中心化。各組件只知道中介者對象,沒法直接相互交流。
  • 外觀類一般能夠轉換爲單例類,由於在大部分狀況下一個外觀對象就足夠了。
  • 外觀模式代理模式的類似之處在於它們都緩存了一個複雜實體並自行對其進行初始化。代理與其服務對象遵循同一接口,使得本身和服務對象能夠互換,在這一點上它與外觀不一樣。

擴展

一個系統有多個外觀類

在外觀模式中,一般只須要一個外觀類,而且此外觀類只有一個實例,換言之它是一個單例類。在不少狀況下爲了節約系統資源,通常將外觀類設計爲單例類。固然這並不意味着在整個系統裏只能有一個外觀類,在一個系統中能夠設計多個外觀類,每一個外觀類都負責和一些特定的子系統交互,向用戶提供相應的業務功能。

不要試圖經過外觀類爲子系統增長新行爲

不要經過繼承一個外觀類在子系統中加入新的行爲,這種作法是錯誤的。外觀模式的用意是爲子系統提供一個集中化和簡化的溝通渠道,而不是向子系統加入新的行爲,新的行爲的增長應該經過修改原有子系統類或增長新的子系統類來實現,不能經過外觀類來實現。

外觀模式與迪米特法則

外觀模式創造出一個外觀對象,將客戶端所涉及的屬於一個子系統的協做夥伴的數量減到最少,使得客戶端與子系統內部的對象的相互做用被外觀對象所取代。外觀類充當了客戶類與子系統類之間的「第三者」,下降了客戶類與子系統類之間的耦合度,外觀模式就是實現代碼重構以便達到「迪米特法則」要求的一個強有力的武器。

抽象外觀類的引入

外觀模式最大的缺點在於違背了「開閉原則」,當增長新的子系統或者移除子系統時須要修改外觀類,能夠經過引入抽象外觀類在必定程度上解決該問題,客戶端針對抽象外觀類進行編程。對於新的業務需求,不修改原有外觀類,而對應增長一個新的具體外觀類,由新的具體外觀類來關聯新的子系統對象,同時經過修改配置文件來達到不修改源代碼並更換外觀類的目的。

Article by wuhb

相關文章
相關標籤/搜索