外观模式:为子系统的一组接口提供一个统一高层入口,隐藏子系统内部复杂细节,客户端只需要调用外观类,不用直接和多个子系统类交互,降低耦合。
角色:
子系统类:完成各自独立功能,对外提供方法,不知道外观类存在
外观 (Facade) 类:持有各个子系统对象,封装组合调用,对外提供简单接口
客户端:只依赖外观类,不直接访问子系统
场景举例
家庭影院:包含灯光、投影仪、音响、DVD 播放器。 看电影时需要:调暗灯光 → 开投影仪 → 开音响 → 播放 DVD; 结束:停止 DVD → 关音响 → 关投影仪 → 开灯。 客户端不用依次调用每一个设备,交给HomeTheaterFacade统一操作。
// ----------------------子系统1:灯光----------------------
class TheaterLight {
public void dim(int level) {
System.out.println("灯光调暗,亮度:" + level);
}
public void on() {
System.out.println("灯光打开");
}
}
// ----------------------子系统2:投影仪----------------------
class Projector {
public void on() {
System.out.println("投影仪开机");
}
public void wideScreenMode() {
System.out.println("投影仪切换宽屏模式");
}
public void off() {
System.out.println("投影仪关机");
}
}
// ----------------------子系统3:音响----------------------
class Stereo {
public void on() {
System.out.println("音响开机");
}
public void setVolume(int vol) {
System.out.println("音响音量设置:" + vol);
}
public void off() {
System.out.println("相机关闭");
}
}
// ----------------------子系统4:DVD播放器----------------------
class DvdPlayer {
public void play(String movie) {
System.out.println("DVD正在播放:" + movie);
}
public void stop() {
System.out.println("DVD停止播放");
}
public void off() {
System.out.println("DVD播放器关机");
}
}
// ----------------------外观Facade 核心类----------------------
/**
* 家庭影院外观类,封装整套复杂操作
*/
public class HomeTheaterFacade {
// 持有所有子系统
private final TheaterLight light;
private final Projector projector;
private final Stereo stereo;
private final DvdPlayer dvdPlayer;
// 构造注入所有子系统
public HomeTheaterFacade(TheaterLight light, Projector projector, Stereo stereo, DvdPlayer dvdPlayer) {
this.light = light;
this.projector = projector;
this.stereo = stereo;
this.dvdPlayer = dvdPlayer;
}
/**
* 对外简单接口:一键看电影
*/
public void watchMovie(String movieName) {
System.out.println("=====准备看电影=====");
light.dim(10);
projector.on();
projector.wideScreenMode();
stereo.on();
stereo.setVolume(60);
dvdPlayer.play(movieName);
}
/**
* 对外简单接口:一键结束观影
*/
public void endMovie() {
System.out.println("\n=====结束电影,关闭设备=====");
dvdPlayer.stop();
dvdPlayer.off();
stereo.off();
projector.off();
light.on();
}
}
// ----------------------客户端测试----------------------
class Client {
public static void main(String[] args) {
// 实例化所有子系统
TheaterLight light = new TheaterLight();
Projector projector = new Projector();
Stereo stereo = new Stereo();
DvdPlayer dvd = new DvdPlayer();
// 创建外观对象
HomeTheaterFacade homeTheater = new HomeTheaterFacade(light, projector, stereo, dvd);
// 客户端只调用外观简单方法,不需要关心内部设备顺序
homeTheater.watchMovie("星际穿越");
homeTheater.endMovie();
}
}
输出结果
=====准备看电影=====
灯光调暗,亮度:10
投影仪开机
投影仪切换宽屏模式
音响开机
音响音量设置:60
DVD正在播放:星际穿越
=====结束电影,关闭设备=====
DVD停止播放
DVD播放器关机
相机关闭
投影仪关机
灯光打开
外观模式要点
不修改子系统代码,只做封装组合,子系统可以继续被客户端直接调用,外观不是屏蔽子系统,只是提供简化入口;
外观类可以有多个,一个子系统可以被多个 Facade 使用;
符合迪米特法则,客户端只和 Facade 交互,减少大量子系统依赖;
典型业务场景:网关封装多方 SDK、支付聚合门面、复杂底层工具封装对外简单 API。
UML 简要说明
客户端 → HomeTheaterFacade(外观)
↓ 组合持有
┌───┬───┴───┬───┐
灯光 投影仪 音响 DVD播放器(各个子系统)本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问