Skip to main content

外观模式 (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();
}
}

有何问题​

这种实现方式存在明显问题:

  1. 客户端需要了解所有子系统的细节,操作繁琐。
  2. 如果子系统增加或变更,客户端代码需要频繁修改。
  3. 客户端与多个子系统高度耦合,维护困难。

解决方案​

外观模式的定义​

为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,使得子系统更易使用。

应用外观模式的思路​

  • 定义一个外观类(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画出外观模式的结构关系:


示例代码​

见上文“外观模式的实现”部分。


模式讲解​

外观模式的功能​

  • 简化客户端操作,隐藏子系统复杂性。
  • 降低客户端与子系统的耦合度。
  • 便于系统分层和维护。

实现成接口​

  • 外观类可实现接口,便于扩展和替换。

使用工厂方法​

  • 可结合工厂方法模式,灵活创建子系统对象。

切换产品簇​

  • 外观模式可用于切换不同的子系统组合,如不同品牌的家居设备。

执行时序图​