C++ 外观模式(Facade Pattern)
一、模式概述
1. 定义
外观模式属于结构型设计模式 ,为一组复杂子系统提供统一高层访问入口 ,对外隐藏子系统内部繁多调用逻辑、执行顺序与依赖关系,让客户端仅通过简洁门面接口即可完成整套业务流程,实现简化调用、层级解耦。
2. 核心思想
- 对内逻辑复杂,对外接口简洁
- 客户端只依赖外观类,不直接耦合众多子系统
- 整合多子系统调用逻辑,封装为固定一键式业务流程
- 严格遵循迪米特法则(最少知识原则)
3. 三大核心角色
| 角色 | 核心职责 | C++ 实现作用 |
|---|---|---|
| 外观类 Facade | 统一入口、流程统筹调度 | 聚合所有子系统,封装组合调用方法,对外暴露简易API |
| 子系统类 SubSystem | 实现独立底层细分功能 | 职责单一,只完成自身功能,互不依赖,可独立复用 |
| 客户端 Client | 发起业务请求 | 仅调用外观接口,完全不接触、不依赖底层子系统 |
4. UML结构关系
- 外观类聚合持有多个子系统实例
- 子系统之间可独立运行,也可内部互相调用
- 调用链路:
客户端 → 外观类 → 各个子系统
二、设计原则与实现要点
1. 编码实现规范
- 子系统:功能单一、职责清晰,仅提供自身业务公有方法
- 外观类:私有成员存储子系统对象,公有方法封装组合流程
- 尽量不修改原有子系统源码,仅在外观层做流程编排
- 可封装多套不同业务流程,满足不同使用场景
2. 两种常用实现方式
- 内部聚合写法:外观类内部直接创建子系统对象,适合小型项目
- 依赖注入写法:通过构造函数传入子系统指针/智能指针,适合大型项目、单元测试解耦
3. 权限管控
- 子系统功能方法仅开放给外观类调用
- 禁止客户端直接实例化调用子系统,统一走外观入口
三、优缺点分析
优点
- 简化调用:复杂多步流程一键调用,降低使用门槛
- 降低耦合:客户端与底层子系统彻底解耦
- 分层清晰:业务层-外观层-底层组件层层级分明
- 统一管控:可在外观层统一添加日志、权限校验、异常捕获
- 易于扩展:新增子系统仅修改外观类,上层客户端无需改动
缺点
- 一定程度违背开闭原则,新增业务组合流程需修改外观类
- 业务量过大易造成外观类臃肿,成为"万能大类"
- 过度封装隐藏底层细节,底层调试排查问题不够直观
- 外观类出现异常,整体业务流程全部受阻
四、适用与不适用场景
适用场景
- 子系统调用步骤繁琐、执行顺序固定的业务场景
- 封装第三方复杂SDK、底层工具库、底层硬件接口
- 系统批量初始化、资源统一释放、多设备联动控制
- 多层架构中做接口收敛层,统一对外暴露服务
- 老旧杂乱代码重构,统一收口整合调用逻辑
不适用场景
- 子系统数量少、调用逻辑简单,无需额外封装
- 业务调用顺序频繁变动,无固定执行流程
- 客户端需要灵活自由组合子系统所有行为
五、外观模式与相近模式区分
1. 外观模式 VS 适配器模式
- 外观模式:整合多个子系统,简化整套调用流程
- 适配器模式:适配单个接口,解决接口参数、格式不兼容问题
2. 外观模式 VS 中介者模式
- 外观模式:单向调用,外观主动调度子系统执行任务
- 中介者模式:双向交互,实现多个对象之间解耦通信
六、基础通用 C++ 完整代码示例
1. 子系统类
cpp
#include <iostream>
using namespace std;
// 子系统A
class SubSystemA
{
public:
void operationA()
{
cout << "子系统A:执行专属业务操作" << endl;
}
};
// 子系统B
class SubSystemB
{
public:
void operationB()
{
cout << "子系统B:执行专属业务操作" << endl;
}
};
// 子系统C
class SubSystemC
{
public:
void operationC()
{
cout << "子系统C:执行专属业务操作" << endl;
}
};
2. 外观统一调度类
cpp
class Facade
{
private:
SubSystemA sysA;
SubSystemB sysB;
SubSystemC sysC;
public:
// 组合业务流程1
void businessProcessOne()
{
cout << "\n===== 执行组合业务流程一 =====" << endl;
sysA.operationA();
sysB.operationB();
}
// 组合业务流程2
void businessProcessTwo()
{
cout << "\n===== 执行组合业务流程二 =====" << endl;
sysB.operationB();
sysC.operationC();
}
// 全流程统一执行
void allProcess()
{
cout << "\n===== 执行全部子系统流程 =====" << endl;
sysA.operationA();
sysB.operationB();
sysC.operationC();
}
};
3. 客户端调用
cpp
int main()
{
Facade facade;
facade.businessProcessOne();
facade.businessProcessTwo();
facade.allProcess();
return 0;
}
基础示例运行结果
===== 执行组合业务流程一 =====
子系统A:执行专属业务操作
子系统B:执行专属业务操作
===== 执行组合业务流程二 =====
子系统B:执行专属业务操作
子系统C:执行专属业务操作
===== 执行全部子系统流程 =====
子系统A:执行专属业务操作
子系统B:执行专属业务操作
子系统C:执行专属业务操作
七、实战场景:家庭影院 C++ 业务案例
1. 硬件设备子系统
cpp
#include <iostream>
#include <string>
using namespace std;
// 灯光子系统
class TheaterLight
{
public:
void dimLight(int level)
{
cout << "灯光调暗至:" << level << "%" << endl;
}
void openLight()
{
cout << "室内灯光全部开启" << endl;
}
};
// 投影仪子系统
class Projector
{
public:
void open()
{
cout << "投影仪成功开启" << endl;
}
void close()
{
cout << "投影仪成功关闭" << endl;
}
};
// 音响功放子系统
class Amplifier
{
public:
void open()
{
cout << "功放音响开启" << endl;
}
void setVolume(int vol)
{
cout << "音响音量设置为:" << vol << endl;
}
void close()
{
cout << "功放音响关闭" << endl;
}
};
// 影院幕布子系统
class Screen
{
public:
void down()
{
cout << "观影幕布缓缓降下" << endl;
}
void up()
{
cout << "观影幕布缓缓升起" << endl;
}
};
// DVD播放子系统
class DVDPlayer
{
public:
void open()
{
cout << "DVD播放器开启" << endl;
}
void playMovie(string movie)
{
cout << "开始播放影片:" << movie << endl;
}
void stop()
{
cout << "影片播放暂停" << endl;
}
void close()
{
cout << "DVD播放器关闭" << endl;
}
};
2. 家庭影院外观门面类
cpp
class HomeTheaterFacade
{
private:
TheaterLight light;
Projector projector;
Amplifier amp;
Screen screen;
DVDPlayer dvd;
public:
// 一键开启观影模式
void watchMovie(string movieName)
{
cout << "\n========== 启动家庭影院观影模式 ==========" << endl;
light.dimLight(10);
screen.down();
projector.open();
amp.open();
amp.setVolume(50);
dvd.open();
dvd.playMovie(movieName);
cout << "========== 观影环境准备完毕 ==========\n" << endl;
}
// 一键关闭所有影院设备
void endMovie()
{
cout << "\n========== 关闭家庭影院所有设备 ==========" << endl;
dvd.stop();
dvd.close();
amp.close();
projector.close();
screen.up();
light.openLight();
cout << "========== 全部设备已断电关闭 ==========\n" << endl;
}
};
3. 业务客户端调用
cpp
int main()
{
HomeTheaterFacade homeTheater;
homeTheater.watchMovie("流浪地球");
homeTheater.endMovie();
return 0;
}
影院案例运行结果
========== 启动家庭影院观影模式 ==========
灯光调暗至:10%
观影幕布缓缓降下
投影仪成功开启
功放音响开启
音响音量设置为:50
DVD播放器开启
开始播放影片:流浪地球
========== 观影环境准备完毕 ==========
========== 关闭家庭影院所有设备 ==========
影片播放暂停
DVD播放器关闭
功放音响关闭
投影仪成功关闭
观影幕布缓缓升起
室内灯光全部开启
========== 全部设备已断电关闭 ==========
八、C++ 高级优化:依赖注入写法
采用智能指针解耦,便于测试、替换子系统实现
cpp
#include <memory>
using namespace std;
class AdvancedFacade
{
private:
shared_ptr<SubSystemA> ptrA;
shared_ptr<SubSystemB> ptrB;
public:
// 构造函数注入子系统对象
AdvancedFacade(shared_ptr<SubSystemA> a, shared_ptr<SubSystemB> b)
: ptrA(a), ptrB(b) {}
void runTask()
{
ptrA->operationA();
ptrB->operationB();
}
};
// 调用示例
/*
int main()
{
auto sysA = make_shared<SubSystemA>();
auto sysB = make_shared<SubSystemB>();
AdvancedFacade facade(sysA, sysB);
facade.runTask();
return 0;
}
*/
九、C++ 项目开发最佳实践
-
目录分层规范
FacadeModule/
├─ SubSystem/ 存放所有底层子系统头文件
└─ Facade.h 对外唯一暴露的外观入口头文件 -
对外项目仅引入外观头文件,隐藏所有子系统内部实现
-
业务体量庞大时,拆分多个细分外观类,避免单一类过于臃肿
-
外观类只负责流程编排与顺序调度,不编写核心业务算法
-
系统初始化、资源批量回收、组件组合调用优先使用外观模式
十、模式总结
外观模式是C++后端、嵌入式、客户端开发中最常用的结构型设计模式 ,核心思想就是收拢底层繁杂接口,对外提供极简统一入口 。
通过外观模式可以大幅简化上层业务代码,降低模块之间耦合度,让代码结构更清晰、后期维护与迭代更加便捷,非常适合固定流程、多组件联动的开发场景。