概念參考:https://blog.csdn.net/carson_ho/article/details/54910625
定義一個高層、統一的接口,通過這個接口實現外部對子系統多個接口的訪問
場景
- 爲一個複雜的子系統對外提供一個簡單的接口
- 提高子系統的獨立性
- 客戶程序與多個子系統之間存在很大的依賴性,系統間解耦,挺高獨立性和可移植性
- 在層次化結構中,可以使用外觀模式定義系統中每一層的入口
優點
- 降低了客戶類與子系統類的耦合度
- 外觀模式對客戶屏蔽了子系統組件,從而簡化了接口,減少了客戶處理的對象數目並使子系統的使用更加簡單
- 降低原有系統的複雜度和系統中的編譯依賴性,並簡化了系統在不同平臺之間的移植過程
缺點
- 在不引入抽象外觀類的情況下,增加新的子系統可能需要修改外觀類或客戶端的源代碼,違背了“開閉原則”
- 不能很好地限制客戶使用子系統類,如果對客戶訪問子系統類做太多的限制則減少了可變性和靈活性
使用
1. 定義子系統功能接口
/**
* 功能接口
*
* @author dkangel
*/
public interface ISubsystem {
/**
* 打開
*/
void turnOn();
/**
* 關閉
*/
void turnOff();
}
2. 實現子系統
/**
* 燈
*
* @author dkangel
*/
public class Light implements ISubsystem {
@Override
public void turnOn() {
System.out.println("開燈");
}
@Override
public void turnOff() {
System.out.println("關燈");
}
}
/**
* 電視
*
* @author dkangel
*/
public class Television implements ISubsystem {
@Override
public void turnOn() {
System.out.println("打開電視");
}
@Override
public void turnOff() {
System.out.println("關閉電視");
}
}
3. 定義外觀類
/**
* 外觀類
*
* @author dkangel
*/
public class Facade {
private ISubsystem light;
private ISubsystem tv;
/**
* 構造函數,實例化成員變量
*
* @param light 燈
* @param tv 電視
*/
public Facade(ISubsystem light, ISubsystem tv) {
this.light = light;
this.tv = tv;
}
/**
* 打開操作
*/
public void on() {
light.turnOn();
tv.turnOn();
}
/**
* 關閉操作
*/
public void off() {
light.turnOff();
tv.turnOff();
}
}
4. 使用
/**
* 外觀模式使用類
*
* @author dkangel
*/
public class Main {
public static void main(String[] args) {
ISubsystem light = new Light();
ISubsystem tv = new Television();
// 不使用外觀模式
turnOnWithNoFacade(light, tv);
turnOffWithNoFacade(light, tv);
// 使用外觀模式,直觀看到使用了外觀模式後,客戶端調用更簡單,知道的東西更少
Facade facade = new Facade(light, tv);
turnOnWithFacade(facade);
turnOffWithFacade(facade);
}
private static void turnOnWithNoFacade(ISubsystem light, ISubsystem tv) {
light.turnOn();
tv.turnOn();
}
private static void turnOffWithNoFacade(ISubsystem light, ISubsystem tv) {
light.turnOff();
tv.turnOff();
}
private static void turnOnWithFacade(Facade facade) {
facade.on();
}
private static void turnOffWithFacade(Facade facade) {
facade.off();
}
}
與適配器模式的區別
- 外觀模式的實現核心主要是——由外觀類去保存各個子系統的引用,實現由一個統一的外觀類去包裝多個子系統類,然而客戶端只需要引用這個外觀類,然後由外觀類來調用各個子系統中的方法
- 適配器模式是將一個對象包裝起來以改變其接口,而外觀是將一羣對象 ”包裝“起來以簡化其接口。它們的意圖是不一樣的,適配器是將接口轉換爲不同接口,而外觀模式是提供一個統一的接口來簡化接口