外觀模式
外觀模式是物件的結構模式,外部與一個子系統的通訊必須通過一個統一的外觀物件進行。外觀模式是一個高層次的介面,使得子系統更易於使用。
醫院的例子
現代的軟體系統都是比較複雜的。假如把醫院比作一個子系統,按照部門職能,這個系統劃分為掛號、門診、劃價、化驗、收費、取藥等。看病的人要與這些部門打交道,就如同一個子系統的客戶端與一個子系統的各個類打交道一樣,不是一件容易的事。
解決這種不便的方法便是引入外觀模式,醫院可以設定一個接待員的位置,由接待員負責代為掛號、劃價、繳費、取藥等。病人只需要接觸接待員,由接待員與各個部門打交道。
外觀模式的結構
外觀模式的結構可以這麼表示:
這個圖中,體現了兩種角色:
1、外觀角色
客戶端呼叫這個角色的方法。此角色知曉相關的子系統的功能和責任,正常情況下,本角色會將所有從客戶端發來的請求委派到響應的子系統中
2、子系統角色
可以同時有一個或多個子系統,每個子系統都不是一個單獨的類,而是一個類的集合。每個子系統都可以被客戶端直接呼叫,或者被外觀角色直接呼叫。子系統並不知道外觀角色的存在,對於子系統而言,外觀僅僅是另外一個客戶端而已
外觀模式示例
模擬三個子系統ModuleA、ModuleB、ModuleC:
public class ModuleA { public void testA() { System.out.println("呼叫Module中的testA方法"); } }
public class ModuleB { public void testB() { System.out.println("呼叫Module中的testB方法"); } }
public class ModuleC { public void testC() { System.out.println("呼叫Module中的testC方法"); } }
模擬一個外觀物件:
public class Facade { public void test() { ModuleA ma = new ModuleA(); ma.testA(); ModuleB mb = new ModuleB(); mb.testB(); ModuleC mc = new ModuleC(); mc.testC(); } }
寫一個客戶端呼叫一下外觀角色:
public static void main(String[] args) { Facade facade = new Facade(); facade.test(); }
執行結果很明顯:
呼叫Module中的testA方法
呼叫Module中的testB方法
呼叫Module中的testC方法
這樣,客戶端不需要親自呼叫子系統的A、B、C模組了,也不需要知道內部系統的實現細節,甚至不需要知道模組A、模組B、模組C的存在,只需要和Facade類互動就好了,從而更好地實現了客戶端和子系統中的三個模組的解耦,讓客戶端更容易地使用子系統。
另外,定義一個外觀類還可以有效地遮蔽內部的細節。因為子系統中有一些方法,是模組之間相互互動用的,並不需要外部呼叫。如果直接呼叫子系統的類方法,會出現一些不需要客戶端知道的方法,這樣既暴露了內部細節,又讓客戶端模迷惑。外觀類就不一樣了,可以只給客戶端提供那些子系統給外部使用的方法。
外觀模式在Java中的應用及解讀
Tomcat中有很多場景都使用到了外觀模式,因為Tomcat中有很多不同的元件,每個元件需要相互通訊,但又不能將自己內部資料過多地暴露給其他元件。用外觀模式隔離資料是個很好的方法,比如Request上使用外觀模式:
比如Servlet,doGet和doPost方法,引數型別是介面HttpServletRequest和介面HttpServletResponse,那麼Tomcat中傳遞過來的真實型別到底是什麼呢?
有過對Java Web專案Debug經驗的肯定會發現,在真正呼叫Servlet前,會經過很多Tomcat方法。反編譯一下javaee.jar包就會看到,傳遞給Tomcat的request和response的真正型別是:
看到返回的都是一個Facade類。因為Request類中很多方法都是元件內部之間互動用的,比如setComet、setReuqestedSessionId等方法,這些方法並不對外公開,但又必須設定為public,因為還要和內部元件互動使用。最好的解決方法就是通過使用一個Facade類,遮蔽掉內部元件之間互動的方法,只提供外部程式要使用的方法。
如果不使用Facade,直接傳遞的是HttpServletRequest和HttpServletResponse,那麼熟悉容器內部運作的開發者可以分別把ServletRequest和ServletResponse向下轉型為HttpServletRequest和HttpServletResponse,這樣就有安全性的問題了。
外觀模式的優點
外觀模式有如下幾個優點:
1、鬆散耦合
外觀模式鬆散了客戶端和子系統的耦合關係,讓子系統內部的模組能更容易擴充套件和維護
2、簡單易用
客戶端不需要了解系統內部的實現,也不需要和眾多子系統內部的模組互動,只需要和外觀類互動就可以了
3、更好地劃分層次
通過合理使用Facade,可以幫助我們更好地劃分層次。有些方法是系統對內的,有些方法是對外的,把需要暴露給外部的功能集中到Facade中,這樣既方便客戶端使用,也很好地隱藏了內部的細節