外观模式(Facade):给子系统一个简单门口
更新时间:2026-08-25。本文按"先看不用模式的困境 → 再用模式重构 → 类图对比分析"的结构,论述外观模式。可运行代码:demos/design-patterns/facade。
一、问题场景:客户端被子系统的内部协作绑架
"开机"要初始化 CPU、内存、硬盘、显卡并按正确顺序协作;"下单"要走库存校验、支付、通知、记账多个子系统。子系统内部协作复杂,但大多数客户端只想要一个简单动作。
二、不使用模式:客户端直接编排所有子系统类
cpp
// 客户端直接操作子系统 5 个类,还要知道顺序
cpu.start(); mem.load(); disk.boot(); gpu.init();
if (disk.check()) { mem.read(); cpu.execute(); } // 编排逻辑散落客户端| 缺陷 | 说明 |
|---|---|
| 客户端知识过载 | 要了解子系统全部类 + 协作顺序(违反 LoD) |
| 编排逻辑重复 | 每个调用点各写一套启动流程 |
| 子系统重构牵连客户端 | 内部类改名/换实现,客户端全崩 |
| 违反 DIP | 客户端直接依赖所有子系统细节 |
不使用模式的类图

三、使用模式:门面统一入口,编排收敛一处
外观模式定义一个门面类,把子系统的一整套协作收敛成少数几个高层方法;客户端只跟门面打交道,子系统内部照常工作。
cpp
// computer_facade.h
class ComputerFacade { // 门面
public:
void start() { // 一个动作 = 子系统正确编排
cpu_.start(); mem_.load(); disk_.boot();
gpu_.init();
}
void shutdown() { gpu_.stop(); disk_.halt(); cpu_.stop(); }
private:
Cpu cpu_; Memory mem_; Disk disk_; Gpu gpu_;
};
// 客户端:只依赖门面
ComputerFacade pc; pc.start();使用模式的类图

四、类图对比与分析
| 维度 | 不使用(直接编排) | 使用外观 |
|---|---|---|
| 客户端知识 | 全部子系统类 + 顺序 | 只知门面 1~2 个方法 |
| 编排逻辑 | 散落各调用点 | 收敛门面一处 |
| 子系统重构 | 牵连所有客户端 | 只改门面内部 |
| LoD 符合度 | 违反(知道太多) | 符合(只跟门面说话) |
| 灵活性 | 客户端可精细控制 | 门面简化 → 精细控制需绕过门面 |
分析结论:外观是"简化"型模式——不改变子系统,只提供一个更友好的入口。它把 LoD 的"直接朋友"落实为门面对象。注意:外观不是"子系统唯一入口",需要精细控制的高级客户端仍可绕过门面直接访问(门面只是快捷方式,不是强制封装的边界)。
五、适用边界
| 适用 | 不适用 |
|---|---|
| 子系统内部复杂、客户端只想要简单动作 | 客户端本就需要精细控制(门面是遮挡) |
| 想给子系统一个稳定入口、降低耦合 | 子系统本身很简单(门面是多余层) |
| 分层架构的层间边界(服务层封装数据层) | 需要严格禁止绕过门面的场景(该用强封装) |
与适配器的区别:适配器"翻译"(接口 A→B 一对一);外观"简化"(多类→单门面一对多)。与中介者的区别:外观封装"对外提供的协作"(给客户端看);中介者封装"内部对象间的协作"(给同事看)。
一句话总结
外观模式用门面类把子系统协作收敛为少数高层方法,客户端只依赖门面即可完成复杂动作——客户端知识面从全部子系统缩到一门面,编排逻辑集中一处,子系统可自由重构;它是 LoD 的直接落实,也是分层架构的常用层间入口。