外觀模式 門面模式 Facade 建立型 設計模式(十三)
外觀模式(FACADE)
又稱為門面模式
原文地址:外觀模式 門面模式 Facade 建立型 設計模式(十三)
意圖
為子系統中的一組介面提供一個一致的介面
Facade模式定義了一個高層介面,這一介面使得這一子系統更加易於使用。
意圖解析
隨著專案的持續發展,系統基本上都是會往功能更全面的方向發展,那麼也就意味著我們的系統將會變得更加複雜。
系統會被劃分為多個單獨的子系統,每個子系統完成一部分功能,通過分工協作完成全部功能。
一個子系統也可能進一步拆分為更小的幾個子系統。
程式中的檔案將會越來越多,相互關聯也會變得更加複雜
當使用一個功能的時候,作為客戶端
你需要弄清楚相關類之間的關係,以及正確的呼叫順序。
比如下圖中
你需要自己識別有哪些子系統,涉及哪些相關的類和方法,你需要自己保證順序(如果功能呼叫依賴順序的話)
如同在醫院裡面,病人需要自己去排隊掛號化驗,跟每個流程的工作人員進行協作
如同在工廠裡面,需要生產一個桌子,你親自用機器生產桌子腿,自己使用機器生產桌面...
如同你去其他公司洽談業務,你單獨跟每個相關業務的人員進行聯絡溝通
你肯定想得到,如果有一箇中間人為你代勞
不需要面對林林總總的子系統、部門、人員...
當你需要某種服務時,只需要告訴這個中間人就好了
這個想法就是外觀模式
有了facade,你就不需要跟每個子系統進行單獨的交流了
如同在醫院裡面,對於VIP,有專人代替你掛號.....
如同在工廠裡面,有一個控制檯機器,你選擇產品,控制檯下發命令安排其他的機器生產具體產品
如同你去其他公司洽談業務,有一個介面人負責與你對接,他們那邊的事情都通過這個人進行安排
外觀模式的意圖含義,如同他的名字一樣,“建築物的正面”
面對一個複雜的大樓,當你在正面遠遠望去,也就只能看到正面
在外觀模式中,形容一個龐大的複雜的系統的一個直觀的介面
藉助於Facade模式
從原來的“客戶端需要跟多個子系統進行互動”,轉變為“只與Facade進行互動”
將客戶端與子系統進行解耦,降低了耦合性,也降低了使用的複雜度
程式碼示例
“關好門窗,防火防盜”這句話有沒有聽過?
回想一下,當你早上準備出門離開家時,你會做什麼?
假設你會關水、關燈、關門窗。
我們建立三個類,水 燈 窗,模擬離開家的場景
package facade; public class Water { public void turnOn() { System.out.println("開啟水龍頭..."); } public void turnOff() { System.out.println("關閉水龍頭..."); } }
package facade; public class Light { public void turnOn() { System.out.println("開燈..."); } public void turnOff() { System.out.println("關燈..."); } }
package facade; public class Window { public void open() { System.out.println("開窗..."); } public void close() { System.out.println("關窗..."); } }
測試程式碼
上面的測試程式碼Test作為客戶端程式,可以看得出來,他直接跟Water Light Window三個類的物件進行互動
他需要呼叫相關的方法
也就是說Test 作為客戶端對於“離家”這一系統的內部邏輯是瞭如指掌的--->需要斷水、關燈、關窗
他也清楚每個類的方法
一方面增加了耦合性,另一方面將子系統的內部細節暴露出來
優化重構
試想下,如果你家是智慧家居,有一個控制檯Facade,或者說有一個手機App
他可以控制整個家庭的裝置
package facade; public class Facade { private Water water = new Water(); private Light light = new Light(); private Window window = new Window(); public void leaveHome(){ water.turnOff(); light.turnOff(); window.close(); } public void backHome(){ light.turnOn(); window.open(); } }
通過這個控制檯,客戶端程式不再需要了解子系統的內部細節,他也不清楚每個類到底有哪些方法
所有的互動都是通過Facade來完成的
結構
Facade 外觀角色
客戶端呼叫角色,知曉子系統的所有功能與職責
通常,Facade會將所有的請求轉發委派到子系統中去,也就是說該角色沒有實際的業務、
SubSystem子系統角色
可以同時有一個或者多個子系統
注意 :子系統並不是說一個單獨的類,而是一個類的集合,這些類根據邏輯功能點被組織在一起
子系統並不知道Facade的存在,對於子系統來說,Facade也就只是一個客戶端程式
外觀模式的結構比較簡單,類似一個“封裝”提取的過程
他的根本原則為迪米特法則,也就是“不要和陌生人說話”,儘可能少的與其他的物件進行互動
通過外觀模式,做到了子系統只與外觀物件互動
門面類個數
在門面模式中,通常只需要一個門面類,並且這個門面類只有一個例項
換句話說他很可能是一個單例
但是並不是說整個系統中只能有一個門面類
門面類的個數要根據系統中子系統的個數以及業務邏輯的情況
總結
當你需要為一個複雜的子系統提供一個簡單的介面時或者希望子系統能夠更加獨立時,可以考慮使用外觀模式
藉助於外觀模式,可以實現客戶端與子系統的解耦,減少客戶端對子系統的依賴性
一旦完成解耦,就意味著子系統有良好的獨立性,也能擁有更好的擴充套件性
因為獨立了,就意味著單獨的子系統修改不會影響其他系統
而且,在多層次結構的系統中,可以使用Facade模式進行層與層之間的互動,將層與層之間的耦合性降低,使他們僅僅通過facade進行互動
總之一句話,降低了使用子系統的複雜程度,降低了耦合程度,滿足迪米特法則----不要和陌生人說話
對客戶端遮蔽了子系統的元件
僅僅通過Facade,大大減少了客戶端所需要處理的物件的數目
對於外觀模式,如果是子系統發生變化,Facade則極有可能需要面臨修改,這不符合開閉原則
外觀模式(門面模式)就如同我們開篇的圖片一樣,作為公司前臺
接待來訪賓客,一切事宜都有她來協調安排組織。
在OOP中,這個“前臺”不僅是一個子系統的“正面”看到的樣子,而且還強調了她的全權負責
她提供所有的業務需要的相關方法,儘管內部呼叫都是子系統中的方法,她提供簡單一致的交流溝通形式
理解了迪米特法則,那麼就比較容易理解外觀模式
外觀模式重點在於提供一個“簡化”“封裝”後的操作控制檯,讓你更容易操作整個系統,他幾乎不會涉及子系統的內部邏輯
否則,門面物件將與子系統的業務邏輯耦合,增加了耦合度。