外觀模式又叫門面模式,屬于結構型模式;是一種通過為多個復雜的子系統提供一個一致的介面,而使這些子系統更加容易被訪問的模式,該模式對外有一個統一介面,外部應用程式不用關心內部子系統的具體細節,這樣會大大降低應用程式的復雜度,提高了程式的可維護性,
現在微服務和模塊化越來越流行,我們都會把一個復雜的系統劃分成幾個較小的子系統,但是這樣做了以后,系統的功能越來越強,子系統會越來越多,客戶對系統的訪問也變得越來越復雜,這時如果系統內部發生改變,客戶端也要跟著改變,這違背了“開閉原則”,也違背了“迪米特法則”,所以有必要為多個子系統提供一個統一的介面,從而降低系統的耦合度,這就是外觀模式的目標,
外觀模式的用意是為子系統提供一個集中化和簡化的溝通管道,而不能向子系統加入新的行為,如果一個外觀模式不能將子系統所有的行為提供給外界,那么可以通過修改門面類或者繼承門面類的辦法,使門面類或其子類能夠將子系統的行為提供給外界,但是,如果一個子系統沒有某個行為,想通過修改門面類或者繼承門面類的辦法來提供這個新的行為是錯誤的,
不使用外觀模式
一個保安系統由兩個錄像機、三個電燈、一個遙感器和一個警報器組成,保安系統的操作人員需要經常將這些儀器啟動和關閉,首先,在不使用門面模式的情況下,操作這個保安系統的操作員必須直接操作所有的這些部件,
不適用外觀模式的UML類圖如下:

如上如所示,Client物件需要參考到所有的錄像機(Camera),電燈(Light),感應器(Sensor)和警報器(Alarm)物件,client物件必須對保安系統全知全能,如果系統引入了一個新的物件,那需要修改的地方就很多了,
錄像機:
package com.charon.facade;
/**
* @className: Camera
* @description: 錄像機系統
* @author: charon
* @create: 2022-03-22 22:27
*/
public class Camera {
/**
* 打開錄像機
*/
public void turnOn(){
System.out.println("錄像機開機,,,,");
}
/**
* 關閉錄像機
*/
public void turnOff(){
System.out.println("錄像機關機,,,,");
}
/**
* 轉動錄像機
*/
public void rotate(int degress){
System.out.println("錄像機轉動 " + degress + "度");
}
}
電燈:
package com.charon.facade;
/**
* @className: Light
* @description: 燈泡
* @author: charon
* @create: 2022-03-22 22:30
*/
public class Light {
/**
* 打開燈泡
*/
public void turnOn(){
System.out.println("燈泡打開,,,,");
}
/**
* 關閉燈泡
*/
public void turnOff(){
System.out.println("燈泡關掉,,,,");
}
/**
* 換燈泡
*/
public void changBulb(){
System.out.println("換了一個燈泡");
}
}
感應器:
package com.charon.facade;
/**
* @className: Sensor
* @description: 感應器
* @author: charon
* @create: 2022-03-22 22:31
*/
public class Sensor {
/**
* 打開感應器
*/
public void activate(){
System.out.println("感應器打開,,,,");
}
/**
* 關閉感應器
*/
public void deactivate(){
System.out.println("感應器關掉,,,,");
}
/**
* 觸發感應器
*/
public void trigger(){
System.out.println("感應器被觸發了,,,");
}
}
警報器:
package com.charon.facade;
/**
* @className: Alarm
* @description: 警報器
* @author: charon
* @create: 2022-03-22 22:33
*/
public class Alarm {
/**
* 打開警報器
*/
public void activate(){
System.out.println("警報器打開,,,,");
}
/**
* 關閉警報器
*/
public void deactivate(){
System.out.println("警報器關掉,,,,");
}
/**
* 拉響警報器
*/
public void ring(){
System.out.println("警報器被拉響了,,,");
}
/**
* 停掉警報器
*/
public void stopRing(){
System.out.println("警報器被關停了,,,");
}
}
測驗:
package com.charon.facade;
/**
* @className: Client
* @description: 外觀模式
* @author: charon
* @create: 2022-03-21 22:30
*/
public class Client {
private static Camera camera1 = new Camera(), camera2 = new Camera();
private static Light light1 = new Light(), light2 = new Light(), light3 = new Light();
private static Sensor sensor = new Sensor();
private static Alarm alarm = new Alarm();
public static void main(String[] args) {
camera1.turnOn();
camera2.turnOn();
light1.turnOn();
light2.turnOn();
light3.turnOn();
sensor.activate();
alarm.activate();
light1.changBulb();
camera1.rotate(180);
sensor.trigger();
alarm.ring();
}
}
列印:
錄像機開機,,,,
錄像機開機,,,,
燈泡打開,,,,
燈泡打開,,,,
燈泡打開,,,,
感應器打開,,,,
警報器打開,,,,
換了一個燈泡
錄像機轉動 180度
感應器被觸發了,,,
警報器被拉響了,,,
使用外觀模式
使用外觀模式的UML類圖如下:

在外觀模式中,就只涉及到門面角色和子系統角色兩種角色了:
- 門面(Facade)角色:客戶端可以呼叫這個角色的方法,此角色知曉相關的(一個或者多個〉子系統的功能和責任,在正常情況下,本角色會將所有從客戶端發來的請求委派到相應的子系統去,
- 子系統(Subsystem)角色:可以同時有一個或者多個子系統,每一個子系統都不是一個單獨的類,而是一個類的集合,每一個子系統都可以被客戶端直接呼叫,或者被門面角色呼叫,子系統并不知道門面的存在,對于子系統而言,門面僅僅是另外一個客戶端而已,
門面類:
package com.charon.facade;
/**
* @className: SecurityFacade
* @description: 門面角色
* @author: charon
* @create: 2022-03-22 23:02
*/
public class SecurityFacade {
private static Camera camera1 = new Camera(), camera2 = new Camera();
private static Light light1 = new Light(), light2 = new Light(), light3 = new Light();
private static Sensor sensor = new Sensor();
private static Alarm alarm = new Alarm();
/**
* 系統啟動
*/
public void activate(){
camera1.turnOn();
camera2.turnOn();
light1.turnOn();
light2.turnOn();
light3.turnOn();
sensor.activate();
alarm.activate();
}
/**
* 系統關閉
*/
public void deactivate(){
camera1.turnOff();
camera2.turnOff();
light1.turnOff();
light2.turnOff();
light3.turnOff();
sensor.deactivate();
alarm.deactivate();
}
}
測驗:
package com.charon.facade;
/**
* @className: Client
* @description: 外觀模式: http://c.biancheng.net/view/1369.html
* @author: charon
* @create: 2022-03-21 22:30
*/
public class Client {
private static SecurityFacade facade = new SecurityFacade();
public static void main(String[] args) {
facade.activate();
facade.deactivate();
}
}
列印:
錄像機開機,,,,
錄像機開機,,,,
燈泡打開,,,,
燈泡打開,,,,
燈泡打開,,,,
感應器打開,,,,
警報器打開,,,,
錄像機關機,,,,
錄像機關機,,,,
燈泡關掉,,,,
燈泡關掉,,,,
燈泡關掉,,,,
感應器關掉,,,,
警報器關掉,,,,
外觀(Facade)模式是“迪米特法則”的典型應用,它有以下主要優點:
- 降低了子系統與客戶端之間的耦合度,使得子系統的變化不會影響呼叫它的客戶類,
- 對客戶屏蔽了子系統組件,減少了客戶處理的物件數目,并使得子系統使用起來更加容易,
- 降低了大型軟體系統中的編譯依賴性,簡化了系統在不同平臺之間的移植程序,因為編譯一個子系統不會影響其他的子系統,也不會影響外觀物件,
外觀(Facade)模式的主要缺點如下:
- 不能很好地限制客戶使用子系統類,很容易帶來未知風險,
- 增加新的子系統可能需要修改外觀類或客戶端的源代碼,違背了“開閉原則”,
外觀模式的應用場景
通常在以下情況下可以考慮使用外觀模式,
- 對分層結構系統構建時,使用外觀模式定義子系統中每層的入口點可以簡化子系統之間的依賴關系,
- 當一個復雜系統的子系統很多時,外觀模式可以為系統設計一個簡單的介面供外界訪問,
- 當客戶端與多個子系統之間存在很大的聯系時,引入外觀模式可將它們分離,從而提高子系統的獨立性和可移植性,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/447136.html
標籤:其他
