外观模式 (Facade)
场景问题
问题案例
考虑这样一个实际的业务场景:一个智能家居系统,用户只需按一个按钮即可完成“回家模式”,系统会自动完成开灯、开空调、播放音乐等一系列操作。每个子系统(灯光、空调、音响)都有复杂的启动流程。
不用模式的解决方案
实现简化版本
最直接的做法是客户端直接操作每个子系统:
public class Light {
public void on() { System.out.println("灯光已打开"); }
}
public class AirConditioner {
public void on() { System.out.println("空调已打开"); }
}
public class Stereo {
public void playMusic() { System.out.println("音乐已播放"); }
}
public class Client {
public static void main(String[] args) {
Light light = new Light();
AirConditioner ac = new AirConditioner();
Stereo stereo = new Stereo();
light.on();
ac.on();
stereo.playMusic();
}
}
有何问题
这种实现方式存在明显问题:
- 客户端需要了解所有子系统的细节,操作繁琐。
- 如果子系统增加或变更,客户端代码需要频繁修改。
- 客户端与多个子系统高度耦合,维护困难。
解决方案
外观模式的定义
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,使得子系统更易使用。
应用外观模式的思路
- 定义一个外观类(Facade),封装多个子系统的复杂操作。
- 客户端只需与外观类交互,无需了解子系统细节。
- 外观类内部协调各子系统完成复杂流程。
外观模式的结构
- Facade:外观类,对外提供统一接口。
- SubSystemA/B/C:子系统,包含具体业务实现。
外观模式的实现
// 子系统
public class Light {
public void on() { System.out.println("灯光已打开"); }
}
public class AirConditioner {
public void on() { System.out.println("空调已打开"); }
}
public class Stereo {
public void playMusic() { System.out.println("音乐已播放"); }
}
// 外观类
public class HomeFacade {
private Light light;
private AirConditioner ac;
private Stereo stereo;
public HomeFacade() {
this.light = new Light();
this.ac = new AirConditioner();
this.stereo = new Stereo();
}
public void arriveHome() {
light.on();
ac.on();
stereo.playMusic();
}
}
使用示例
public class Client {
public static void main(String[] args) {
HomeFacade facade = new HomeFacade();
facade.arriveHome();
}
}
外观重写示例
示例结构
用mermaid画出外观模式的结构关系:
示例代码
见上文“外观模式的实现”部分。
模式讲解
外观模式的功能
- 简化客户端操作,隐藏子系统复杂性。
- 降低客户端与子系统的耦合度。
- 便于系统分层和维护。
实现成接口
- 外观类可实现接口,便于扩展和替换。
使用工厂方法
- 可结合工厂方法模式,灵活创建子系统对象。
切换产品簇
- 外观模式可用于切换不同的子系统组合,如不同品牌的家居设备。