目录
一、场景【案例来源】
1 题目描述
小明家的电源总开关控制了家里的三个设备:空调、台灯和电视机。每个设备都有独立的开关密码,分别用数字1、2和3表示。即输入1时,空调关闭,输入2时,台灯关闭,输入3时,电视机关闭,当输入为4时,表示要关闭所有设备。请你使用外观模式编写程序来描述电源总开关的操作。
2 输入描述
第一行是一个整数 N(1 <= N <= 100),表示后面有 N 行输入。
接下来的 N 行,每行包含一个数字,表示对应设备的开关操作(1表示关闭空调,2表示关闭台灯,3表示关闭电视机,4表示关闭所有设备)。
3 输出描述
输出关闭所有设备后的状态,当输入的数字不在1-4范围内时,输出Invalid device code.
4 输入示例
4
1
2
3
4
5 输出示例
Air Conditioner is turned off.
Desk Lamp is turned off.
Television is turned off.
All devices are off.
二、如果不采用外观模式
1、实现
- 客户端:
public class Application {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
for (int i = 0; i < n; i++) {
int code = scanner.nextInt();
switch (code) {
case 1:
new AirConditioner().off();
break;
case 2:
new DeskLamp().off();
break;
case 3:
new Television().off();
break;
case 4:
new AllDevice().off();
break;
default: throw new RuntimeException("Invalid code, code must in [1, 4]");
}
}
}
}
- 子系统1(空调AirConditioner):
public class AirConditioner {
public void off() {
System.out.println("Air Conditioner is turned off.");
}
}
- 子系统2(台灯DeskLamp)
public class DeskLamp {
public void off() {
System.out.println("Desk Lamp is turned off.");
}
}
- 子系统3(台灯Television)
public class Television {
public void off() {
System.out.println("Television is turned off.");
}
}
- 子系统4(所有设备AllDevice)
public class AllDevice {
public void off() {
System.out.println("All devices are off.");
}
}
2、问题
- 客户端的代码要尽可能抽象,而非具体。否则,当增加一个子系统时,或者关闭设备改为打开设备时,我们不得不修改客户端代码。
三、采用外观模式
- 外观是一种结构型设计模式, 对各种子系统(可以简单理解为用到的类)进行封装,并提供一个简单 (但有限) 的接口供客户端调用。
1、实现
- 客户端:
@ComponentScan
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);
DeviceOffFacade deviceOff = applicationContext.getBean(DeviceOffFacade.class);
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
for (int i = 0; i < n; i++) {
int code = scanner.nextInt();
deviceOff.off(code);
}
}
}
- 外观类:
@Component
public class DeviceOffFacade {
@Autowired
private AirConditioner airConditioner;
@Autowired
private DeskLamp deskLamp;
@Autowired
private Television television;
@Autowired
private AllDevice allDevice;
public void off(int code) {
switch (code) {
case 1:
airConditioner.off();
break;
case 2:
deskLamp.off();
break;
case 3:
television.off();
break;
case 4:
allDevice.off();
break;
default: throw new RuntimeException("Invalid code, code must in [1, 4]");
}
}
}
2、优点
- 实际开发中,通过Spring注入各种子系统的bean(如上所示),然后将这些相关bean封装在一个外观类中。可以简化客户端调用各种子系统的代码。
- 如果当前的DeviceOffFacade不满足需求,例如,新需求:当人回家时,智能门检测到住户的人脸后,先开客厅的灯,然后打开客厅的窗帘等。我们可以定义新的外观类,如DeviceArrangeFacade,提供一个arrange(xxx)方法。
四、个人思考
- 这应该是我学过的最简单的设计模式了… 思想极其纯粹。在实际开发中,不知不觉就应用过这种设计模式,将屎山代码做一下简单的封装,这样闻起来就没那么臭了:)。