外觀模式
有句話說這個(gè)世界就是個(gè)草臺(tái)班子,只不過排面做的好看而已,里面都是一包糠。這句話來形容外觀模式非常準(zhǔn)確,外觀模式又叫門面模式,顧名思義一個(gè)系統(tǒng)我不管你里面有多復(fù)雜有多少屎山代碼,我只要求你提供的接口好用,簡單就行,即門面要有排面!用專業(yè)的話講是一種通過為多個(gè)復(fù)雜的子系統(tǒng)提供一個(gè)一致的接口,而使這些子系統(tǒng)更加容易被訪問的模式。該模式對外有一個(gè)統(tǒng)一接口,外部應(yīng)用程序不用關(guān)心內(nèi)部子系統(tǒng)的具體的細(xì)節(jié),這樣會(huì)大大降低應(yīng)用程序的復(fù)雜度,提高了程序的可維護(hù)性。
外觀(Facade)模式是“迪米特法則”的典型應(yīng)用,還記得這個(gè)“迪米特法則”嗎?如果兩個(gè)軟件實(shí)體無須直接通信,那么就不應(yīng)當(dāng)發(fā)生直接的相互調(diào)用,可以通過第三方轉(zhuǎn)發(fā)該調(diào)用。其目的是降低類之間的耦合度,提高模塊的相對獨(dú)立性。下圖中的系統(tǒng)內(nèi)部是很復(fù)雜的,左邊這個(gè)系統(tǒng)對外的調(diào)用關(guān)系更是很亂的,內(nèi)部的不堪直接暴露給觀眾。而使用外觀模式,則可以設(shè)置一個(gè)門面或者叫做代理對象,統(tǒng)一由這個(gè)門面來對外提供簡單的、整潔的調(diào)用接口。這就是外觀模式!
外觀(Facade)模式包含以下主要角色:
- 外觀(Facade,又稱為門面)角色:為多個(gè)子系統(tǒng)對外提供一個(gè)共同的接口。
- 子系統(tǒng)(Sub System)角色:實(shí)現(xiàn)系統(tǒng)的部分功能,客戶可以通過外觀角色訪問它。
案例
現(xiàn)在流行智能家居,只需要一個(gè)中控平臺(tái)即可操作全屋家具,這個(gè)中控可以是一個(gè)手機(jī)或者一個(gè)智能音箱(小愛同學(xué))。以前我們要開燈需要去找開關(guān)、開空調(diào)電視機(jī)要去找遙控器,很煩也很亂?,F(xiàn)在我們只需要和中控進(jìn)行交互而不需要去對每個(gè)設(shè)備進(jìn)行交互。因此,可以使用外觀模式解決,類圖如下:
代碼
首先定義各個(gè)電器實(shí)體類如下:
// 定義電視類
public class TV {
private String name;
private Boolean state;
public void on(){
state = true;
System.out.println("電視被打開");
}
public void off(){
state = false;
System.out.println("電視被關(guān)閉");
}
}
// 定義燈類
public class Light {
private String name;
private Boolean state;
public void on(){
state = true;
System.out.println("燈被打開");
}
public void off(){
state = false;
System.out.println("燈被關(guān)閉");
}
}
// 定義空調(diào)類
public class AirCondition {
private String name;
private Boolean state;
public void on(){
state = true;
System.out.println("空調(diào)被打開");
}
public void off(){
state = false;
System.out.println("空調(diào)被關(guān)閉");
}
}
使用統(tǒng)一的外觀類(門面類)管理電器:
public class ApplicationFacade {
private Light light;
private TV tv;
private AirCondition airCondition;
public ApplicationFacade() {
light = new Light();
tv = new TV();
airCondition = new AirCondition();
}
private void onAll() {
light.on();
tv.on();
airCondition.on();
}
private void offAll() {
light.off();
tv.off();
airCondition.off();
}
public void say(String msg) {
switch (msg) {
case "我回家了":
onAll();
break;
case "我出門了":
offAll();
break;
case "打開電視":
tv.on();
break;
case "關(guān)閉電視":
tv.off();
break;
case "打開空調(diào)":
airCondition.on();
break;
case "關(guān)閉空調(diào)":
airCondition.off();
break;
case "打開燈":
light.on();
break;
case "關(guān)閉燈":
light.off();
break;
default:
System.out.println("我聽不懂你在說什么");
}
}
}
客戶端進(jìn)行調(diào)用測試:
public class Main {
public static void main(String[] args) {
ApplicationFacade app = new ApplicationFacade();
app.say("我回家了");
app.say("關(guān)閉電視");
app.say("我出門了");
}
}
輸出:
燈被打開
電視被打開
空調(diào)被打開
電視被關(guān)閉
燈被關(guān)閉
電視被關(guān)閉
空調(diào)被關(guān)閉
好處
- 降低了子系統(tǒng)與客戶端之間的耦合度,使得子系統(tǒng)的變化不會(huì)影響調(diào)用它的客戶類。
- 對客戶屏蔽了子系統(tǒng)組件,減少了客戶處理的對象數(shù)目,并使得子系統(tǒng)使用起來更加容易。
缺點(diǎn)
- 不符合開閉原則,修改很麻煩
使用場景
- 對分層結(jié)構(gòu)系統(tǒng)構(gòu)建時(shí),使用外觀模式定義子系統(tǒng)中每層的入口點(diǎn)可以簡化子系統(tǒng)之間的依賴關(guān)系。
- 當(dāng)一個(gè)復(fù)雜系統(tǒng)的子系統(tǒng)很多時(shí),外觀模式可以為系統(tǒng)設(shè)計(jì)一個(gè)簡單的接口供外界訪問。
- 當(dāng)客戶端與多個(gè)子系統(tǒng)之間存在很大的聯(lián)系時(shí),引入外觀模式可將它們分離,從而提高子系統(tǒng)的獨(dú)立性和可移植性。
典型案例
Slf4j
日志框架是典型的外觀模式(門面模式),它本身并不實(shí)現(xiàn)日志的具體功能,需要結(jié)合log4j、log4j2或者logback等具體日志工具來使用,它只提供統(tǒng)一的調(diào)用接口。如下圖所示:文章來源:http://www.zghlxwxcb.cn/news/detail-816083.html
參考內(nèi)容:
傳智播客系列設(shè)計(jì)模式筆記
https://www.runoob.com/design-pattern/facade-pattern.html
https://www.bilibili.com/video/BV1aS4y1Y7iP文章來源地址http://www.zghlxwxcb.cn/news/detail-816083.html
到了這里,關(guān)于結(jié)構(gòu)型設(shè)計(jì)模式——外觀模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!