在軟件開發(fā)過程中,客戶端程序經(jīng)常會與復(fù)雜系統(tǒng)的內(nèi)部子系統(tǒng)進(jìn)行耦合,從而導(dǎo)致客戶端程序隨著子系統(tǒng)的變化而變化,然而為了將復(fù)雜系統(tǒng)的內(nèi)部子系統(tǒng)與客戶端之間的依賴解耦,從而就有了外觀模式,也稱作 ”門面“模式。下面就具體介紹下外觀模式。
成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供龍陵網(wǎng)站建設(shè)、龍陵做網(wǎng)站、龍陵網(wǎng)站設(shè)計(jì)、龍陵網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、龍陵企業(yè)網(wǎng)站模板建站服務(wù),十余年龍陵做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
外觀模式提供了一個(gè)統(tǒng)一的接口,用來訪問子系統(tǒng)中的一群接口。外觀定義了一個(gè)高層接口,讓子系統(tǒng)更容易使用。使用外觀模式時(shí),我們創(chuàng)建了一個(gè)統(tǒng)一的類,用來包裝子系統(tǒng)中一個(gè)或多個(gè)復(fù)雜的類,客戶端可以直接通過外觀類來調(diào)用內(nèi)部子系統(tǒng)中方法,從而外觀模式讓客戶和子系統(tǒng)之間避免了緊耦合。
介紹了外觀模式的定義之后,讓我們具體看看外觀模式的由來以及實(shí)現(xiàn),下面與學(xué)校中一個(gè)選課系統(tǒng)為例來解釋外觀模式,例如在選課系統(tǒng)中,有注冊課程子系統(tǒng)和通知子系統(tǒng),在不使用外觀模式的情況下,客戶端必須同時(shí)保存注冊課程子系統(tǒng)和通知子系統(tǒng)兩個(gè)引用,如果后期這兩個(gè)子系統(tǒng)發(fā)生改變時(shí),此時(shí)客戶端的調(diào)用代碼也要隨之改變,這樣就沒有很好的可擴(kuò)展性,下面看看不使用外觀模式下選課系統(tǒng)的實(shí)現(xiàn)方式和客戶端調(diào)用代碼:
////// 不使用外觀模式的情況 /// 此時(shí)客戶端與三個(gè)子系統(tǒng)都發(fā)送了耦合,使得客戶端程序依賴與子系統(tǒng) /// 為了解決這樣的問題,我們可以使用外觀模式來為所有子系統(tǒng)設(shè)計(jì)一個(gè)統(tǒng)一的接口 /// 客戶端只需要調(diào)用外觀類中的方法就可以了,簡化了客戶端的操作 /// 從而讓客戶和子系統(tǒng)之間避免了緊耦合 /// class Client { static void Main(string[] args) { SubSystemA a = new SubSystemA(); SubSystemB b = new SubSystemB(); SubSystemC c = new SubSystemC(); a.MethodA(); b.MethodB(); c.MethodC(); Console.Read(); } } // 子系統(tǒng)A public class SubSystemA { public void MethodA() { Console.WriteLine("執(zhí)行子系統(tǒng)A中的方法A"); } } // 子系統(tǒng)B public class SubSystemB { public void MethodB() { Console.WriteLine("執(zhí)行子系統(tǒng)B中的方法B"); } } // 子系統(tǒng)C public class SubSystemC { public void MethodC() { Console.WriteLine("執(zhí)行子系統(tǒng)C中的方法C"); } }
然而外觀模式可以解決我們上面所說的問題,下面具體看看使用外觀模式的實(shí)現(xiàn):
////// 以學(xué)生選課系統(tǒng)為例子演示外觀模式的使用 /// 學(xué)生選課模塊包括功能有: /// 驗(yàn)證選課的人數(shù)是否已滿 /// 通知用戶課程選擇成功與否 /// 客戶端代碼 /// class Student { private static RegistrationFacade facade = new RegistrationFacade(); static void Main(string[] args) { if (facade.RegisterCourse("設(shè)計(jì)模式", "Learning Hard")) { Console.WriteLine("選課成功"); } else { Console.WriteLine("選課失敗"); } Console.Read(); } } // 外觀類 public class RegistrationFacade { private RegisterCourse registerCourse; private NotifyStudent notifyStu; public RegistrationFacade() { registerCourse = new RegisterCourse(); notifyStu = new NotifyStudent(); } public bool RegisterCourse(string courseName, string studentName) { if (!registerCourse.CheckAvailable(courseName)) { return false; } return notifyStu.Notify(studentName); } } #region 子系統(tǒng) // 相當(dāng)于子系統(tǒng)A public class RegisterCourse { public bool CheckAvailable(string courseName) { Console.WriteLine("正在驗(yàn)證課程 {0}是否人數(shù)已滿", courseName); return true; } } // 相當(dāng)于子系統(tǒng)B public class NotifyStudent { public bool Notify(string studentName) { Console.WriteLine("正在向{0}發(fā)生通知", studentName); return true; } } #endregion
使用了外觀模式之后,客戶端只依賴與外觀類,從而將客戶端與子系統(tǒng)的依賴解耦了,如果子系統(tǒng)發(fā)生改變,此時(shí)客戶端的代碼并不需要去改變。外觀模式的實(shí)現(xiàn)核心主要是——由外觀類去保存各個(gè)子系統(tǒng)的引用,實(shí)現(xiàn)由一個(gè)統(tǒng)一的外觀類去包裝多個(gè)子系統(tǒng)類,然而客戶端只需要引用這個(gè)外觀類,然后由外觀類來調(diào)用各個(gè)子系統(tǒng)中的方法。然而這樣的實(shí)現(xiàn)方式非常類似適配器模式,然而外觀模式與適配器模式不同的是:適配器模式是將一個(gè)對象包裝起來以改變其接口,而外觀是將一群對象 ”包裝“起來以簡化其接口。它們的意圖是不一樣的,適配器是將接口轉(zhuǎn)換為不同接口,而外觀模式是提供一個(gè)統(tǒng)一的接口來簡化接口。
看完外觀模式的實(shí)現(xiàn)之后,為了幫助理清外觀模式中類之間的關(guān)系,下面給出上面實(shí)現(xiàn)代碼中類圖:
然而對于外觀模式而言,是沒有一個(gè)一般化的類圖描述,下面演示一個(gè)外觀模式的示意性對象圖來加深大家對外觀模式的理解:
在上面的對象圖中有兩個(gè)角色:
門面(Facade)角色:客戶端調(diào)用這個(gè)角色的方法。該角色知道相關(guān)的一個(gè)或多個(gè)子系統(tǒng)的功能和責(zé)任,該角色會將從客戶端發(fā)來的請求委派帶相應(yīng)的子系統(tǒng)中去。
子系統(tǒng)(subsystem)角色:可以同時(shí)包含一個(gè)或多個(gè)子系統(tǒng)。每個(gè)子系統(tǒng)都不是一個(gè)單獨(dú)的類,而是一個(gè)類的集合。每個(gè)子系統(tǒng)都可以被客戶端直接調(diào)用或被門面角色調(diào)用。對于子系統(tǒng)而言,門面僅僅是另外一個(gè)客戶端,子系統(tǒng)并不知道門面的存在。
優(yōu)點(diǎn):
外觀模式對客戶屏蔽了子系統(tǒng)組件,從而簡化了接口,減少了客戶處理的對象數(shù)目并使子系統(tǒng)的使用更加簡單。
外觀模式實(shí)現(xiàn)了子系統(tǒng)與客戶之間的松耦合關(guān)系,而子系統(tǒng)內(nèi)部的功能組件是緊耦合的。松耦合使得子系統(tǒng)的組件變化不會影響到它的客戶。
缺點(diǎn):
如果增加新的子系統(tǒng)可能需要修改外觀類或客戶端的源代碼,這樣就違背了”開——閉原則“(不過這點(diǎn)也是不可避免)。
在以下情況下可以考慮使用外觀模式:
外一個(gè)復(fù)雜的子系統(tǒng)提供一個(gè)簡單的接口
提供子系統(tǒng)的獨(dú)立性
在層次化結(jié)構(gòu)中,可以使用外觀模式定義系統(tǒng)中每一層的入口。其中三層架構(gòu)就是這樣的一個(gè)例子。
到這里外觀模式的介紹就結(jié)束了,外觀模式,為子系統(tǒng)的一組接口提供一個(gè)統(tǒng)一的接口,該模式定義了一個(gè)高層接口,這一個(gè)高層接口使的子系統(tǒng)更加容易使用。并且外觀模式可以解決層結(jié)構(gòu)分離、降低系統(tǒng)耦合度和為新舊系統(tǒng)交互提供接口功能。