解析C#設(shè)計(jì)模式編程中外觀模式Facade Pattern的應(yīng)用
實(shí)例引入
在家庭影院中,有燈光,屏幕,投影機(jī),功放機(jī),DVD 播放器這幾個(gè)基本的工具:
- 燈光,可以關(guān)閉燈光和打開燈光。
- 投影機(jī),可以打開和關(guān)閉投影機(jī)。
- 屏幕,可以打開和關(guān)閉。
- 功放機(jī),可以關(guān)閉音量和打開音量。
- DVD 播放器,可以打開播放器和關(guān)閉播放器。
以最普通的方式實(shí)現(xiàn)觀看電影,類圖如下所示:
按照類圖所示,如果要觀看電影,必須在客戶端執(zhí)行下面的操作:先打開投影儀,再打開功放機(jī),再打開屏幕,再打開 DVD 播放機(jī),再打開燈光,在經(jīng)歷了這么多操作后,才可以看一場(chǎng)電影。而在關(guān)閉電影的時(shí)候,也要先關(guān)閉投影儀,再關(guān)閉功放機(jī),再關(guān)閉屏幕,再關(guān)閉 DVD 播放機(jī),再關(guān)閉燈光。哦,這是太復(fù)雜了?。?!在客戶端居然有那么多操作,如果有一些用戶不知道如何使用其中的一個(gè)工具,那他便看不了電影!
上面其實(shí)反映的是現(xiàn)今軟件開發(fā)系統(tǒng)中的一個(gè)比較常見的現(xiàn)象,客戶端程序經(jīng)常和復(fù)雜系統(tǒng)的內(nèi)部子系統(tǒng)產(chǎn)生直接聯(lián)系,導(dǎo)致客戶程序隨著子系統(tǒng)的變化而變化。要想解決上面的這一串問題,必須要簡(jiǎn)化客戶程序與子系統(tǒng)之間的交互接口,解除客戶程序和子系統(tǒng)之間的耦合,而外觀模式正好可以解決這個(gè)問題。
外觀模式(Facade)的定義:為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,用來訪問子系統(tǒng)中的一群接口。
此模式定義了一個(gè)高層的接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用。簡(jiǎn)單的說,就是外觀模式將一個(gè)或者多個(gè)類的復(fù)雜的操作進(jìn)行了隱藏,只顯示出一個(gè)一致的界面供客戶端使用。需要注意的是,外觀模式僅僅是給你提供了更為直接和容易的操作方式,它并沒有把原來的子系統(tǒng)進(jìn)行隔離,所以,如果你還需要子系統(tǒng)類的更高層的功能,還是可以使用原來的子系統(tǒng)的,這個(gè)是外觀模式的一大優(yōu)點(diǎn)。通過外觀模式可以將子系統(tǒng)的多個(gè)接口上建立一個(gè)高層接口,并且將這個(gè)高層接口提供給客戶端使用,這樣便可以解除掉客戶端和復(fù)雜子系統(tǒng)之間的耦合。
通過上圖可以看出,外觀模式實(shí)現(xiàn)提供簡(jiǎn)單的接口(OpenMovie 和 CloseMovie)給客戶端,也給客戶端和子系統(tǒng)之間實(shí)現(xiàn)了解耦。下面通過代碼來實(shí)現(xiàn)上面的這個(gè) Demo。
幾個(gè)播放工具的代碼:
using System; namespace Facade { /// <summary> /// 投影儀 /// </summary> public class Projector { public void OpenProjector() { Console.WriteLine("打開投影儀"); } public void CloseProjector() { Console.WriteLine("關(guān)閉投影儀"); } public void SetWideScreen() { Console.WriteLine("投影儀狀態(tài)為寬屏模式"); } public void SetStandardScreen() { Console.WriteLine("投影儀狀態(tài)為標(biāo)準(zhǔn)模式"); } } } using System; namespace Facade { /// <summary> /// 功放機(jī) /// </summary> public class Amplifier { public void OpenAmplifier() { Console.WriteLine("打開功放機(jī)"); } public void CloseAmplifier() { Console.WriteLine("關(guān)閉功放機(jī)"); } } } using System; namespace Facade { /// <summary> /// 屏幕 /// </summary> public class Screen { public void OpenScreen() { Console.WriteLine("打開屏幕"); } public void CloseScreen() { Console.WriteLine("關(guān)閉屏幕"); } } } using System; namespace Facade { /// <summary> /// DVD播放器 /// </summary> public class DVDPlayer { public void OpenDVDPlayer() { Console.WriteLine("打開 DVD 播放器"); } public void CloseDVDPlayer() { Console.WriteLine("關(guān)閉 DVD 播放器"); } } } using System; namespace Facade { /// <summary> /// 燈光 /// </summary> public class Light { public void OpenLight() { Console.WriteLine("打開燈光"); } public void CloseLight() { Console.WriteLine("關(guān)閉燈光"); } } }
外觀類中的代碼:
namespace Facade { /// <summary> /// 定義一個(gè)外觀 /// </summary> public class MovieFacade { /// <summary> /// 在外觀類中必須保存有子系統(tǒng)中各個(gè)對(duì)象 /// </summary> private Projector projector; private Amplifier amplifier; private Screen screen; private DVDPlayer dvdPlayer; private Light light; public MovieFacade() { projector = new Projector(); amplifier = new Amplifier(); screen = new Screen(); dvdPlayer = new DVDPlayer(); light = new Light(); } /// <summary> /// 打開電影 /// </summary> public void OpenMovie() { //先打開投影儀 projector.OpenProjector(); //再打開功放 amplifier.OpenAmplifier(); //再打開屏幕 screen.OpenScreen(); //再打開 DVD dvdPlayer.OpenDVDPlayer(); //再打開燈光 light.OpenLight(); } /// <summary> /// 關(guān)閉電影 /// </summary> public void CloseMovie() { //關(guān)閉投影儀 projector.CloseProjector(); //關(guān)閉功放 amplifier.CloseAmplifier(); //關(guān)閉屏幕 screen.CloseScreen(); //關(guān)閉 DVD dvdPlayer.CloseDVDPlayer(); //關(guān)閉燈光 light.CloseLight(); } } }
客戶端代碼:
using System; namespace FacadeTest { class Program { static void Main(string[] args) { Facade.MovieFacade movie = new Facade.MovieFacade(); Facade.Projector projector = new Facade.Projector(); //首先是觀看電影 movie.OpenMovie(); Console.WriteLine(); //然后是將投影儀模式調(diào)到寬屏模式 projector.SetWideScreen(); //再將投影儀模式調(diào)回普通模式 projector.SetStandardScreen(); Console.WriteLine(); //最后就是關(guān)閉電影了 movie.CloseMovie(); Console.ReadKey(); } } }
從上例中可以看出,可以在客戶端中使用子系統(tǒng)中的內(nèi)容,即外觀模式并沒有把子系統(tǒng)和客戶端隔離開來,只是提供了整潔的接口給客戶端,如果客戶端想訪問復(fù)雜子系統(tǒng)中的接口時(shí)還是一樣的可以訪問的。比如在上面的 Demo 中的設(shè)置了寬屏和普通等模式。
外觀模式的結(jié)構(gòu)總結(jié)
看完外觀模式的實(shí)現(xiàn)之后,為了幫助理清外觀模式中類之間的關(guān)系,下面給出上面實(shí)現(xiàn)代碼中類圖:
然而對(duì)于外觀模式而言,是沒有一個(gè)一般化的類圖描述,下面演示一個(gè)外觀模式的示意性對(duì)象圖來加深大家對(duì)外觀模式的理解:
在上面的對(duì)象圖中有兩個(gè)角色:
門面(Facade)角色:客戶端調(diào)用這個(gè)角色的方法。該角色知道相關(guān)的一個(gè)或多個(gè)子系統(tǒng)的功能和責(zé)任,該角色會(huì)將從客戶端發(fā)來的請(qǐng)求委派帶相應(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)用。對(duì)于子系統(tǒng)而言,門面僅僅是另外一個(gè)客戶端,子系統(tǒng)并不知道門面的存在。
外觀的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
外觀模式對(duì)客戶屏蔽了子系統(tǒng)組件,從而簡(jiǎn)化了接口,減少了客戶處理的對(duì)象數(shù)目并使子系統(tǒng)的使用更加簡(jiǎn)單。
外觀模式實(shí)現(xiàn)了子系統(tǒng)與客戶之間的松耦合關(guān)系,而子系統(tǒng)內(nèi)部的功能組件是緊耦合的。松耦合使得子系統(tǒng)的組件變化不會(huì)影響到它的客戶。
缺點(diǎn):
如果增加新的子系統(tǒng)可能需要修改外觀類或客戶端的源代碼,這樣就違背了”開——閉原則“(不過這點(diǎn)也是不可避免)。
使用場(chǎng)景
在以下情況下可以考慮使用外觀模式:
外一個(gè)復(fù)雜的子系統(tǒng)提供一個(gè)簡(jiǎn)單的接口
提供子系統(tǒng)的獨(dú)立性
在層次化結(jié)構(gòu)中,可以使用外觀模式定義系統(tǒng)中每一層的入口。其中三層架構(gòu)就是這樣的一個(gè)例子。
總結(jié)
到這里外觀模式的介紹就結(jié)束了,外觀模式,為子系統(tǒng)的一組接口提供一個(gè)統(tǒng)一的接口,該模式定義了一個(gè)高層接口,這一個(gè)高層接口使的子系統(tǒng)更加容易使用。并且外觀模式可以解決層結(jié)構(gòu)分離、降低系統(tǒng)耦合度和為新舊系統(tǒng)交互提供接口功能。
上一篇:舉例講解C#編程中對(duì)設(shè)計(jì)模式中的單例模式的運(yùn)用
欄 目:C#教程
下一篇:使用設(shè)計(jì)模式中的工廠方法模式進(jìn)行C#編程的示例講解
本文標(biāo)題:解析C#設(shè)計(jì)模式編程中外觀模式Facade Pattern的應(yīng)用
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6682.html
您可能感興趣的文章
- 01-10C#編程實(shí)現(xiàn)自定義熱鍵的方法
- 01-10C#編程獲取資源文件中圖片的方法
- 01-10深入淺出23種設(shè)計(jì)模式
- 01-10C#編程自學(xué)之?dāng)?shù)據(jù)類型和變量二
- 01-10C#編程自學(xué)之開篇介紹
- 01-10C#編程自學(xué)之?dāng)?shù)據(jù)類型和變量三
- 01-10C#編程自學(xué)之運(yùn)算符和表達(dá)式
- 01-10C#編程自學(xué)之類和對(duì)象
- 01-10C#編程和Visual Studio使用技巧(下)
- 01-10C#編程自學(xué)之?dāng)?shù)據(jù)類型和變量一


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁(yè)無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法