Java設計模式11:外觀模式

五月的倉頡發表於2015-10-25

外觀模式

外觀模式是物件的結構模式,外部與一個子系統的通訊必須通過一個統一的外觀物件進行。外觀模式是一個高層次的介面,使得子系統更易於使用。

 

醫院的例子

現代的軟體系統都是比較複雜的。假如把醫院比作一個子系統,按照部門職能,這個系統劃分為掛號、門診、劃價、化驗、收費、取藥等。看病的人要與這些部門打交道,就如同一個子系統的客戶端與一個子系統的各個類打交道一樣,不是一件容易的事。

解決這種不便的方法便是引入外觀模式,醫院可以設定一個接待員的位置,由接待員負責代為掛號、劃價、繳費、取藥等。病人只需要接觸接待員,由接待員與各個部門打交道。

 

外觀模式的結構

外觀模式的結構可以這麼表示:

這個圖中,體現了兩種角色:

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中,這樣既方便客戶端使用,也很好地隱藏了內部的細節

相關文章