一、引言
快12點半了,要開始今天的寫作了。很快,轉眼設計模式已經寫了十個了,今天我們要講【結構型】設計模式的第五個模式,該模式是【外觀模式】,英文名稱是:Facade Pattern。我們先從名字上來理解一下“外觀模式”。我看到了“外觀”這個詞語,就想到了“外表”這個詞語,兩者有着很相近的意思。就拿談戀愛來說,“外表”很重要,如果第一眼看着很舒服、有眼緣,那就有交往下去的可能。如果長的“三寸釘、枯樹皮”,估計就夠嗆了。在這方面,“外觀”和“外表”有着相同的作用。在軟件系統中,要完成一個功能,需要很多接口調用,不僅增加了開發難度,也增加了調試成本和維護的復雜度。不如我們把這些接口再封裝一次,給一個很好的“外觀”,讓使用者使用更方便,只需調用一個接口,就可以完成以前調用多個接口的來完成任務,這就方便了。這個模式很簡單,大家很容易理解,可能大家在編碼的過程中已經不止一次使用過該模式了,只是不知道名字罷了。現實生活中這樣的例子很多,舉不勝舉,來一幅圖,大家看看就明白了。
圖一:
二、外觀模式的詳細介紹
2.1、動機(Motivate)
在軟件系統開發的過程中,當組件的客戶(即外部接口,或客戶程序)和組件中各種復雜的子系統有了過多的耦合,隨着外部客戶程序和各子系統的演化,這種過多的耦合面臨很多變化的挑戰。如何簡化外部客戶程序和系統間的交互接口?如何將外部客戶程序的演化和內部子系統的變化之間的依賴相互解耦?
2.2、意圖(Intent)
為子系統中的一組接口提供一個一致的界面,Facade模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。 ——《設計模式》GoF
2.3、結構圖(Structure)
2.4、模式的組成
外觀模式包含如下兩個角色:
(1)、外觀角色(Facade):在客戶端可以調用它的方法,在外觀角色中可以知道相關的(一個或者多個)子系統的功能和責任;在正常情況下,它將所有從客戶端發來的請求委派到相應的子系統去,傳遞給相應的子系統對象處理。
(2)、子系統角色(SubSystem):在軟件系統中可以有一個或者多個子系統角色,每一個子系統可以不是一個單獨的類,而是一個類的集合,它實現子系統的功能;每一個子系統都可以被客戶端直接調用,或者被外觀角色調用,它處理由外觀類傳過來的請求;子系統並不知道外觀的存在,對於子系統而言,外觀角色僅僅是另外一個客戶端而已。
2.5、外觀模式的具體實現
馬上就到“雙十一”了,人們又開始瘋狂的購買了。其實購買的過程很復雜,但是我們在購買的過程只需要選擇自己喜歡的商品,也可以加入購物車,最后點擊付款就完成了。其實這個過程沒有那么簡單。我們下面就模仿一下購買的過程吧。
購買過程有幾點必須要做的事情:
1、身份驗證安全,沒有認證是無效用戶。
2、系統安全,檢查系統環境,防止注入、跨站和偽造等攻擊
3、網銀安全,檢查付款地址的有效性,檢查網關是否正常
1 namespace 外觀模式的實現 2 { 3 /// <summary> 4 /// 不使用外觀模式的情況 5 /// 此時客戶端與三個子系統都發送了耦合,使得客戶端程序依賴與子系統 6 /// 為了解決這樣的問題,我們可以使用外觀模式來為所有子系統設計一個統一的接口 7 /// 客戶端只需要調用外觀類中的方法就可以了,簡化了客戶端的操作 8 /// 從而讓客戶和子系統之間避免了緊耦合 9 /// </summary> 10 class Client 11 { 12 static void Main(string[] args) 13 { 14 SystemFacade facade=new SystemFacade(); 15 facade.Buy(); 16 Console.Read(); 17 } 18 } 19 20 // 身份認證子系統A 21 public class AuthoriationSystemA 22 { 23 public void MethodA() 24 { 25 Console.WriteLine("執行身份認證"); 26 } 27 } 28 29 // 系統安全子系統B 30 public class SecuritySystemB 31 { 32 public void MethodB() 33 { 34 Console.WriteLine("執行系統安全檢查"); 35 } 36 } 37 38 // 網銀安全子系統C 39 public class NetBankSystemC 40 { 41 public void MethodC() 42 { 43 Console.WriteLine("執行網銀安全檢測"); 44 } 45 } 46 47 //更高層的Facade 48 public class SystemFacade 49 { 50 private AuthoriationSystemA auth; 51 private SecuritySystemB security; 52 private NetBankSystemC netbank; 53 54 public SystemFacade() 55 { 56 auth=new AuthoriationSystemA(); 57 security=new SecuritySystemB(); 58 netbank=new NetBankSystemC(); 59 } 60 61 public void Buy() 62 { 63 auth.MethodA();//身份認證子系統 64 security.MethodB();//系統安全子系統 65 netbank.MethodC();//網銀安全子系統 66 67 Console.WriteLine("我已經成功購買了!"); 68 } 69 } 70 }
這個模式很簡單,就話不多說了。
三、外觀模式的實現要點:
1、一個系統可以有幾個門面類
在門面模式中,通常只需要一個門面類,並且此門面類只有一個實例,換言之它是一個單例類。當然這並不意味着在整個系統里只有一個門面類,而僅僅是說對每一個子系統只有一個門面類。或者說,如果一個系統有好幾個子系統的話,每一個子系統都有一個門面類,整個系統可以有數個門面類。
2、為子系統增加新行為
初學者往往以為通過繼承一個門面類便可在子系統中加入新的行為,這是錯誤的。門面模式的用意是為子系統提供一個集中化和簡化的溝通管道,而不能向子系統加入新的行為。比如醫院中的接待員並不是醫護人員,接待員並不能為病人提供醫療服務。
3、Facade有助於建立層次結構的系統,實現了子系統與客戶之間的松耦合關系,子系統內部的功能組件往往是緊耦合的。松耦合關系使得子系統的組件變化不會影響到它的客戶。Facade消除了復雜的循環依賴關系。這一點在客戶程序與子系統分別實現的時候格外重要。
4、從客戶程序的角度來看,Facade模式不僅簡化了整個組件系統的接口,同時對於組件內部與外部客戶程序來說,從某種程度上也達到了一種“解耦”的效果——內部子系統的任何變化不會影響到Facade接口的變化。
3.1】、外觀模式的優點:
(1)、外觀模式對客戶屏蔽了子系統組件,從而簡化了接口,減少了客戶處理的對象數目並使子系統的使用更加簡單。
(2)、外觀模式實現了子系統與客戶之間的松耦合關系,而子系統內部的功能組件是緊耦合的。松耦合使得子系統的組件變化不會影響到它的客戶。
3.2】、外觀模式的缺點:
(1)、如果增加新的子系統可能需要修改外觀類或客戶端的源代碼,這樣就違背了”開——閉原則“(不過這點也是不可避免)。
3.3】、在以下情況下可以考慮使用外觀模式:
(1)、外一個復雜的子系統提供一個簡單的接口
(2)、提供子系統的獨立性
(3)、在層次化結構中,可以使用外觀模式定義系統中每一層的入口。其中三層架構就是這樣的一個例子。
四、.NET 中外觀模式的實現
外觀模式在FCL里面運用還是很多的,多數情況是單個類的情況,在Asp.Net里面,有很多復合控件,比如:Login控件,可以登錄,可以認證,可以保存登錄用戶信息。其實,外觀模式更多的是應用在業務系統當中,效果更好。
五、總結
這個模式很簡單,就不說了,就稍微做一下小結。Facade設計模式更注重從架構的層次去看整個系統,而不是單個類的層次。Facade很多時候更是一種架構設計模式。注意區分Facade模式、Adapter模式、Bridge模式與Decorator模式:
Facade模式注重簡化接口
Adapter模式注重轉換接口
Bridge模式注重分離接口(抽象)與其實現
Decorator模式注重穩定接口的前提下為對象擴展功能