1. 模式定义
外观模式(Facade Pattern) 为子系统中的一组接口提供一个统一的简化接口。它定义了一个高层接口,使子系统更容易使用。
2. 核心思想
- 封装复杂的子系统内部逻辑
- 提供简化的客户端调用接口
- 降低客户端与子系统的耦合度
3. 逻辑结构图
Facade
+operation()
SubsystemA
+operationA()
SubsystemB
+operationB()
SubsystemC
+operationC()
Client
+main()
4. 应用场景
典型场景:
-
复杂系统的简化访问
- 编译器系统(词法分析、语法分析、代码生成)
- 视频转换工具(解码、编码、混流)
-
分层系统的入口
- 业务逻辑层对数据访问层的封装
- 服务层对多个DAO的协调
-
遗留系统适配
- 为新系统提供统一接口
- 隔离旧系统的复杂调用
-
第三方库封装
- 简化第三方API调用
- 替换第三方库时减少影响
5. C++代码示例
场景:家庭影院系统
cpp
#include <iostream>
#include <string>
// 子系统类:投影仪
class Projector {
public:
void on() { std::cout << "投影仪已打开" << std::endl; }
void off() { std::cout << "投影仪已关闭" << std::endl; }
void setInput(const std::string& source) {
std::cout << "投影仪输入源设置为: " << source << std::endl;
}
};
// 子系统类:音响系统
class SoundSystem {
public:
void on() { std::cout << "音响系统已打开" << std::endl; }
void off() { std::cout << "音响系统已关闭" << std::endl; }
void setVolume(int level) {
std::cout << "音量设置为: " << level << std::endl;
}
void setMode(const std::string& mode) {
std::cout << "音效模式: " << mode << std::endl;
}
};
// 子系统类:蓝光播放器
class BluRayPlayer {
public:
void on() { std::cout << "蓝光播放器已打开" << std::endl; }
void off() { std::cout << "蓝光播放器已关闭" << std::endl; }
void play(const std::string& movie) {
std::cout << "正在播放电影: " << movie << std::endl;
}
void stop() { std::cout << "停止播放" << std::endl; }
};
// 子系统类:灯光系统
class Lighting {
public:
void dim(int level) {
std::cout << "灯光亮度调至: " << level << "%" << std::endl;
}
void on() { std::cout << "灯光已打开" << std::endl; }
};
// 外观类:家庭影院外观
class HomeTheaterFacade {
private:
Projector* projector;
SoundSystem* soundSystem;
BluRayPlayer* bluRayPlayer;
Lighting* lighting;
public:
HomeTheaterFacade(Projector* proj, SoundSystem* sound,
BluRayPlayer* bluray, Lighting* light)
: projector(proj), soundSystem(sound),
bluRayPlayer(bluray), lighting(light) {}
// 简化的观影模式
void watchMovie(const std::string& movie) {
std::cout << "\n=== 准备观影模式 ===" << std::endl;
lighting->dim(20); // 调暗灯光
projector->on(); // 打开投影
projector->setInput("BluRay"); // 设置输入源
soundSystem->on(); // 打开音响
soundSystem->setVolume(30); // 设置音量
soundSystem->setMode("影院");
bluRayPlayer->on(); // 打开播放器
bluRayPlayer->play(movie); // 播放电影
std::cout << "=== 开始观影 ===\n" << std::endl;
}
// 简化的结束观影
void endMovie() {
std::cout << "\n=== 结束观影 ===" << std::endl;
bluRayPlayer->stop(); // 停止播放
bluRayPlayer->off(); // 关闭播放器
soundSystem->off(); // 关闭音响
projector->off(); // 关闭投影
lighting->on(); // 打开灯光
std::cout << "=== 观影结束 ===\n" << std::endl;
}
};
// 客户端代码
int main() {
// 创建子系统对象
Projector projector;
SoundSystem soundSystem;
BluRayPlayer bluRayPlayer;
Lighting lighting;
// 创建外观对象
HomeTheaterFacade homeTheater(&projector, &soundSystem,
&bluRayPlayer, &lighting);
// 客户端只需调用简化接口
homeTheater.watchMovie("盗梦空间");
homeTheater.endMovie();
return 0;
}
6. 执行流程时序图
Lighting BluRayPlayer SoundSystem Projector Facade Client Lighting BluRayPlayer SoundSystem Projector Facade Client watchMovie("盗梦空间") dim(20) on() setInput("BluRay") on() setVolume(30) setMode("影院") on() play("盗梦空间") 准备就绪
7. 优缺点分析
优点
✅ 简化调用 :客户端只需与外观交互,无需了解子系统细节
✅ 降低耦合 :客户端与子系统的依赖关系减弱
✅ 提高灵活性 :子系统内部变化不影响客户端
✅ 分层清晰:为复杂系统提供明确的分层边界
缺点
❌ 可能违背开闭原则 :新增子系统可能需要修改外观类
❌ 可能成为上帝对象 :外观类可能过度集中功能
❌ 性能开销:增加一层间接调用
8. 与其他模式的关系
-
外观模式 vs 适配器模式
- 外观:提供新接口简化调用
- 适配器:转换接口使不兼容的类能协作
-
外观模式 vs 中介者模式
- 外观:单向调用,客户端→外观→子系统
- 中介者:双向协作,各组件通过中介通信
9. 最佳实践建议
- 按功能维度封装:一个外观类负责一组相关操作
- 避免外观类过于庞大:考虑拆分成多个外观类
- 可选择是否暴露子系统:高级用户可直接调用子系统
- 配合单例模式:外观类通常设计为单例
10. 实际应用示例
cpp
// 游戏引擎中的外观模式应用
class GameEngine {
public:
void startGame() {
graphics.init();
physics.init();
audio.init();
input.init();
// 复杂的初始化流程...
}
void update(float deltaTime) {
input.process();
physics.update(deltaTime);
graphics.render();
audio.update();
}
};
外观模式特别适合在系统重构、框架设计、第三方库集成等场景中使用,能够有效提升代码的可维护性和可读性。