09.C++设计模式-外观模式

1. 模式定义

外观模式(Facade Pattern) 为子系统中的一组接口提供一个统一的简化接口。它定义了一个高层接口,使子系统更容易使用。

2. 核心思想

  • 封装复杂的子系统内部逻辑
  • 提供简化的客户端调用接口
  • 降低客户端与子系统的耦合度

3. 逻辑结构图

Facade
+operation()
SubsystemA
+operationA()
SubsystemB
+operationB()
SubsystemC
+operationC()
Client
+main()

4. 应用场景

典型场景:
  1. 复杂系统的简化访问

    • 编译器系统(词法分析、语法分析、代码生成)
    • 视频转换工具(解码、编码、混流)
  2. 分层系统的入口

    • 业务逻辑层对数据访问层的封装
    • 服务层对多个DAO的协调
  3. 遗留系统适配

    • 为新系统提供统一接口
    • 隔离旧系统的复杂调用
  4. 第三方库封装

    • 简化第三方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. 最佳实践建议

  1. 按功能维度封装:一个外观类负责一组相关操作
  2. 避免外观类过于庞大:考虑拆分成多个外观类
  3. 可选择是否暴露子系统:高级用户可直接调用子系统
  4. 配合单例模式:外观类通常设计为单例

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();
    }
};

外观模式特别适合在系统重构、框架设计、第三方库集成等场景中使用,能够有效提升代码的可维护性和可读性。

相关推荐
xiaoye-duck8 小时前
《C++ 工具库实战》gflags 命令行参数解析库详解
c++·第三方库
狂奔的sherry9 小时前
C++ 宏生成访问函数的代价:访问权限、调试和类型检查
c++·宏·编译·预处理器·类型检查
划破黑暗的第一缕曙光10 小时前
[C++]:5.STL:string(2)
java·c++·redis
小超人诞生日记13 小时前
C++ 异常机制详解:从抛出捕获到异常安全
c++·算法
多弗朗皮卡丘13 小时前
C++的IO流
开发语言·c++·io流·文件io流
xiangyun6114 小时前
C++ 手撕 shared_ptr:引用计数与控制块到底长什么样?
开发语言·c++·算法·面试·stl
SunkingYang14 小时前
C++14 vs C++17:新特性对比与用法指南
c++·新特性·用法·c++14·示例·c++17
SunkingYang15 小时前
C++ Lambda 表达式原理详解
c++·lambda·理论·原理·表达式
xiaoye-duck16 小时前
《C++ 工具库实战》GTest 单元测试:断言、全局环境、局部夹具与底层原理
c++·单元测试·第三方库
学逆向的16 小时前
C++ 匿名命名空间
开发语言·c++·网络安全