什么是外观模式?
外观模式(Facade Pattern)是一种结构型设计模式,它提供了一个统一的接口,用来访问子系统中的一组接口。外观模式定义了一个高层接口,这个接口使得子系统更加容易使用。
为什么使用外观模式?
- 简化复杂系统的访问
- 降低子系统与客户端的耦合度
- 提供统一的接口
- 隐藏系统的复杂性
实现示例
1. 基本实现
// 子系统类A
public class SubSystemA {
public void operationA() {
System.out.println("子系统A的操作");
}
}
// 子系统类B
public class SubSystemB {
public void operationB() {
System.out.println("子系统B的操作");
}
}
// 子系统类C
public class SubSystemC {
public void operationC() {
System.out.println("子系统C的操作");
}
}
// 外观类
public class Facade {
private SubSystemA systemA;
private SubSystemB systemB;
private SubSystemC systemC;
public Facade() {
systemA = new SubSystemA();
systemB = new SubSystemB();
systemC = new SubSystemC();
}
// 提供给客户端的简单接口
public void operation() {
systemA.operationA();
systemB.operationB();
systemC.operationC();
}
}2. 实际应用示例:家庭影院系统
// 各个子系统
public class Screen {
public void down() {
System.out.println("屏幕降下");
}
public void up() {
System.out.println("屏幕升起");
}
}
public class Projector {
public void on() {
System.out.println("投影仪打开");
}
public void off() {
System.out.println("投影仪关闭");
}
public void focus() {
System.out.println("投影仪调焦");
}
}
public class SoundSystem {
public void on() {
System.out.println("音响系统打开");
}
public void off() {
System.out.println("音响系统关闭");
}
public void setVolume(int volume) {
System.out.println("设置音量: " + volume);
}
}
public class DvdPlayer {
public void on() {
System.out.println("DVD播放器打开");
}
public void off() {
System.out.println("DVD播放器关闭");
}
public void play() {
System.out.println("DVD开始播放");
}
public void stop() {
System.out.println("DVD停止播放");
}
}
// 家庭影院外观类
public class HomeTheaterFacade {
private Screen screen;
private Projector projector;
private SoundSystem soundSystem;
private DvdPlayer dvdPlayer;
public HomeTheaterFacade() {
screen = new Screen();
projector = new Projector();
soundSystem = new SoundSystem();
dvdPlayer = new DvdPlayer();
}
// 观影模式
public void watchMovie() {
System.out.println("=== 准备观影 ===");
screen.down();
projector.on();
projector.focus();
soundSystem.on();
soundSystem.setVolume(50);
dvdPlayer.on();
dvdPlayer.play();
}
// 结束观影
public void endMovie() {
System.out.println("=== 结束观影 ===");
dvdPlayer.stop();
dvdPlayer.off();
soundSystem.off();
projector.off();
screen.up();
}
}3. 计算机启动示例
// 子系统组件
public class CPU {
public void freeze() { System.out.println("CPU冻结"); }
public void jump(long position) { System.out.println("CPU跳转到: " + position); }
public void execute() { System.out.println("CPU执行指令"); }
}
public class Memory {
public void load(long position, String data) {
System.out.println("内存加载数据: " + data + " 到位置: " + position);
}
}
public class HardDrive {
public String read(long lba, int size) {
return "从硬盘读取的数据";
}
}
// 计算机外观类
public class ComputerFacade {
private CPU cpu;
private Memory memory;
private HardDrive hardDrive;
public ComputerFacade() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
public void start() {
cpu.freeze();
memory.load(0, hardDrive.read(0, 1024));
cpu.jump(0);
cpu.execute();
}
}4. 使用示例
public class Client {
public static void main(String[] args) {
// 家庭影院示例
HomeTheaterFacade homeTheater = new HomeTheaterFacade();
homeTheater.watchMovie();
System.out.println("\n电影播放中...\n");
homeTheater.endMovie();
// 计算机启动示例
ComputerFacade computer = new ComputerFacade();
computer.start();
}
}外观模式的优点
- 简化了客户端的调用
- 实现了子系统与客户端的松耦合
- 提供了一个简单的接口
- 隐藏了系统的复杂性
外观模式的缺点
- 不符合开闭原则,修改需要修改外观类
- 可能产生过多的外观类
- 不能很好地限制客户端对子系统的使用
适用场景
- 需要为复杂系统提供一个简单接口
- 需要将系统分层,使用外观模式定义子系统中每层的入口点
- 需要将一个复杂的子系统与其客户端解耦
- 需要构建一个层次结构的子系统时
与其他模式的关系
- 适配器模式:适配器改变接口以匹配客户的需求,外观模式提供简化的接口
- 单例模式:外观类通常是单例的
- 抽象工厂模式:可以与外观模式一起使用来提供一个复杂子系统的接口
总结
外观模式是一种使用频率很高的设计模式,它通过提供一个统一的接口,简化了复杂系统的使用。在实际开发中,当需要简化复杂系统的访问时,外观模式是一个很好的选择。
参考资料
- 《Design Patterns: Elements of Reusable Object-Oriented Software》
- 《Head First Design Patterns》
- Java API 文档
- Spring Framework 源码

