外觀模式提供一個統一的接口,用來訪問子系統中的一羣接口。外觀定義了一個高層接口,讓子系統更容易訪問。編程
封裝交互,簡化調用緩存
假設必須在代碼中使用某個複雜的庫或框架中的衆多對象。正常狀況下,須要負責全部對象的初始化工做、管理其依賴關係並按正確的順序執行方法等。bash
最終,程序中類的業務邏輯將與第三方類的實現細節緊密耦合,使得理解和維護代碼的工做很難進行。框架
外觀類爲包含許多活動部分的複雜子系統提供一個簡單的接口。與直接調用子系統相比,外觀提供的功能可能比較有效,但卻包含了客戶端真正關心的功能。ide
若是程序須要與包含幾十種功能的複雜庫整合,但只須要使用其中部分功能,那麼使用外觀模式會比較方便。網站
例如,上傳貓咪搞笑短視頻到社交媒體網站的應用可能會用到專業的視頻轉換庫,但它只需使用一個包含 encode(filename, format)
方法(以文件名與文件格式爲參數進行編碼的方法)的類便可。在建立這個類並將其鏈接到視頻轉換庫後,一個外觀模式就完成了。ui
當經過電話給商店下達訂單時,接線員就是該商店的全部服務和部門的外觀。接線員提供了一個同購物系統、支付網關和各類送貨服務進行互動的簡單語音接口。編碼
外觀(Facade)提供了一種訪問特定子系統功能的便捷方式,其瞭解如何重定向客戶端請求,知曉如何操做一切活動部件。spa
複雜子系統(Complex Subsystem)由數十個不一樣對象構成。若是要用這些對象完成有意義的工做,你必須深刻了解子系統的實現細節,好比按照正確順序初始化對象和爲其提供正確格式的數據。設計
子系統類不會意識到外觀的存在,它們在系統內運做而且相互之間可直接進行交互。
客戶端(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()
複製代碼
一個系統有多個外觀類
在外觀模式中,一般只須要一個外觀類,而且此外觀類只有一個實例,換言之它是一個單例類。在不少狀況下爲了節約系統資源,通常將外觀類設計爲單例類。固然這並不意味着在整個系統裏只能有一個外觀類,在一個系統中能夠設計多個外觀類,每一個外觀類都負責和一些特定的子系統交互,向用戶提供相應的業務功能。
不要試圖經過外觀類爲子系統增長新行爲
不要經過繼承一個外觀類在子系統中加入新的行爲,這種作法是錯誤的。外觀模式的用意是爲子系統提供一個集中化和簡化的溝通渠道,而不是向子系統加入新的行爲,新的行爲的增長應該經過修改原有子系統類或增長新的子系統類來實現,不能經過外觀類來實現。
外觀模式與迪米特法則
外觀模式創造出一個外觀對象,將客戶端所涉及的屬於一個子系統的協做夥伴的數量減到最少,使得客戶端與子系統內部的對象的相互做用被外觀對象所取代。外觀類充當了客戶類與子系統類之間的「第三者」,下降了客戶類與子系統類之間的耦合度,外觀模式就是實現代碼重構以便達到「迪米特法則」要求的一個強有力的武器。
抽象外觀類的引入
外觀模式最大的缺點在於違背了「開閉原則」,當增長新的子系統或者移除子系統時須要修改外觀類,能夠經過引入抽象外觀類在必定程度上解決該問題,客戶端針對抽象外觀類進行編程。對於新的業務需求,不修改原有外觀類,而對應增長一個新的具體外觀類,由新的具體外觀類來關聯新的子系統對象,同時經過修改配置文件來達到不修改源代碼並更換外觀類的目的。
Article by wuhb