好不容易盼到週末啦!Jungle想喫點好的犒勞自己!喫什麼呢?回鍋肉!是的,喫回鍋肉!
可是這過程好麻煩啊,先得去市場裏買肉,買回來得洗好,然後切好,再炒肉,最後才能喫上!不僅過程繁雜,而且Jungle還得跟市場、廚房打交道,想想都頭大。
如果有個廚師就好了,Jungle直接告訴廚師“我要喫回鍋肉”,20分鐘後廚師直接端上來就開喫。而中間那些買肉洗肉切肉的過程Jungle統統不關心了,而且Jungle也不必再關心市場和廚房,直接和廚師說句話就ok!真是方便!
在這個例子中,廚師整合了一系列複雜的過程,外界(Jungle)只需與廚師交互即可。在軟件設計模式中,有一類設計模式正式如此——外觀模式。
1.外觀模式簡介
外觀模式是一種使用頻率較高的設計模式,它提供一個外觀角色封裝多個複雜的子系統,簡化客戶端與子系統之間的交互,方便客戶端使用。外觀模式可以降低系統的耦合度。如果沒有外觀類,不同的客戶端在需要和多個不同的子系統交互,系統中將存在複雜的引用關係,如下圖。引入了外觀類,原有的複雜的引用關係都由外觀類實現,不同的客戶端只需要與外觀類交互。
外觀模式:
爲子系統中的一組接口提供一個統一的入口。外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
外觀模式的應用很多,比如瀏覽器,用戶要查找什麼東西,不論是瀏覽知乎、騰訊或者CSDN,用戶都只需要打開瀏覽器即可,剩下的搜索工作由瀏覽器完成。
2.外觀模式結構
外觀模式的UML結構圖如下所示:
外觀模式一共有以下角色:
- Facade(外觀角色):外觀角色可以知道多個相關子系統的功能,它將所有從客戶端發來的請求委派給相應的子系統,傳遞給相應的子系統處理。
- SubSystem(子系統角色):子系統是一個類,或者由多個類組成的類的集合,它實現子系統具體的功能。
3.外觀模式代碼實例
電腦主機(Mainframe)中只需要按下主機的開機按鈕(powerOn),即可調用其他硬件設備和軟件的啓動方法,如內存(Memory)的自檢(selfCheck)、CPU的運行(run)、硬盤(HardDisk)的讀取(read)、操作系統(OS)的載入(load)等。如果某一過程發生錯誤則電腦開機失敗。
這裏Jungle用外觀模式來模擬該過程,該例子UML圖如下:
3.1.子系統類
本例中一共有4個子系統,因此設計4個類:Memory、CPU、HardDisk和OS,並且每個子系統都有自己獨立的流程。
//子系統:內存
class Memory
{
public:
Memory(){}
void selfCheck(){
printf("…………內存自檢……\n");
}
};
//子系統:CPU
class CPU
{
public:
CPU(){}
void run(){
printf("…………運行CPU運行……\n");
}
};
//子系統:硬盤
class HardDisk
{
public:
HardDisk(){}
void read(){
printf("…………讀取硬盤……\n");
}
};
//子系統:操作系統
class OS
{
public:
OS(){}
void load(){
printf("…………載入操作系統……\n");
}
};
3.2.外觀類設計
//外觀類
class Facade
{
public:
Facade(){
memory = new Memory();
cpu = new CPU();
hardDisk = new HardDisk();
os = new OS();
}
void powerOn(){
printf("正在開機……\n");
memory->selfCheck();
cpu->run();
hardDisk->read();
os->load();
printf("開機完成!\n");
}
private:
Memory *memory;
CPU *cpu;
HardDisk *hardDisk;
OS *os;
};
3.3.客戶端代碼示例
#include <iostream>
#include "FacadePattern.h"
int main()
{
Facade *facade = new Facade();
facade->powerOn();
printf("\n\n");
system("pause");
return 0;
}
看到了嗎,客戶端的代碼就是如此簡單,跟子系統無關!
3.4.效果
4.總結
優點:
- 外觀模式使得客戶端不必關心子系統組件,減少了與客戶端交互的對象的數量,簡化了客戶端的編程;
- 外觀模式可以大大降低系統的耦合度;
- 子系統的變化並不需要修改客戶端,只需要適當修改外觀類即可;
- 子系統之間不會相互影響。
缺點:
- 如果需要增加或者減少子系統,需要修改外觀類,違反開閉原則;
- 並不能限制客戶端直接與子系統交互,但如果加強限制,又使得系統靈活度降低。
適用場景:
- 爲訪問一系列複雜的子系統提供一個統一的、簡單的入口,可以使用外觀模式;
- 客戶端與多個子系統之間存在很大依賴,但在客戶端編程,又會增加系統耦合度,且使客戶端編程複雜,可以使用外觀模式。
歡迎關注知乎專欄:Jungle是一個用Qt的工業Robot
歡迎關注Jungle的微信公衆號:Jungle筆記