C++ 桥接模式(结构型)

桥接模式本质上是通过组合将对外接口类(抽象部分)与实现类(实现部分)解耦,但"组合"只是其实现手段,核心目标是支持两者的独立扩展。以下是详细分析:

1. 桥接模式的核心结构

桥接模式包含两个关键部分:

  • 抽象部分(Abstraction):定义对外接口,持有实现类的引用(组合关系)。
  • 实现部分(Implementor):定义底层操作接口,由具体实现类完成。

关键点

  • 组合关系:抽象部分通过组合(而非继承)持有实现类的实例,实现解耦。
  • 独立变化:抽象部分和实现部分可分别扩展,互不影响。

2. 代码示例:接口类与实现类的组合

以下C++示例中,Shape(抽象部分)通过组合 Renderer(实现部分)解耦两者:

cpp 复制代码
#include <iostream>
using namespace std;

// 实现部分:渲染器接口
class Renderer {
public:
    virtual void render() = 0;
    virtual ~Renderer() {}
};

// 具体实现类:OpenGL渲染器
class OpenGLRenderer : public Renderer {
public:
    void render() override {
        cout << "使用OpenGL渲染" << endl;
    }
};

// 抽象部分:图形接口
class Shape {
protected:
    Renderer* renderer; // 组合实现类
public:
    Shape(Renderer* r) : renderer(r) {}
    virtual void draw() = 0;
};

// 具体抽象类:圆形(扩展抽象部分)
class Circle : public Shape {
public:
    Circle(Renderer* r) : Shape(r) {}
    void draw() override {
        cout << "绘制圆形,";
        renderer->render();
    }
};

// 客户端代码
int main() {
    Renderer* renderer = new OpenGLRenderer();
    Shape* circle = new Circle(renderer);
    circle->draw(); // 输出:绘制圆形,使用OpenGL渲染
    delete renderer;
    delete circle;
    return 0;
}

说明

  • Shape 是对外接口类,定义 draw() 方法。
  • Renderer 是实现接口,OpenGLRenderer 是具体实现类。
  • Shape 通过组合 Renderer 实现解耦,两者可独立扩展(如新增 VulkanRendererSquare 类)。

3. 桥接模式与组合的关系

特性 说明
组合关系 抽象部分持有实现类的引用,通过方法调用实现协作。
解耦目标 抽象部分和实现部分可独立变化(如修改图形类型不影响渲染逻辑)。
与简单组合的区别 桥接模式的组合是设计模式层面的解耦,而简单组合是代码结构上的聚合。

那么有人会问:

我只要对外接口抽象类和具体实现类的组合,不需要扩展可以吗?属于桥接模式吗?

答案是这种属于简单组合,不属于桥接模式,桥接模式除了这个还必须要有抽象类与实现类的扩展。这就属于过度设计与开闭原则的平衡问题了。

关键判断标准

特征 桥接模式 普通组合
解耦目标 抽象与实现独立变化 代码结构聚合,无解耦需求
扩展性 支持新增抽象类型或实现方式 扩展需修改现有代码
典型场景 跨平台图形渲染、多支付方式 日志记录、工具类聚合

结论:若组合关系未实现抽象与实现的独立扩展,则不属于桥接模式。

4. 设计建议

  1. 明确需求:若需支持多维度独立变化(如图形+渲染),选择桥接模式;否则使用普通组合。
  2. 遵循开闭原则:桥接模式通过解耦使系统更易扩展,但会增加类数量,需权衡复杂度。
  3. 避免过度设计:简单场景中,直接组合或继承可能更清晰。

5. 适用场景总结

桥接模式适用于以下场景:

  1. 多维度独立变化:如图形类型(圆形、矩形)和渲染方式(OpenGL、Vulkan)。
  2. 避免继承爆炸 :通过组合替代多重继承(如 RedCircleBlueRectangle 的类爆炸问题)。
  3. 隐藏实现细节:客户端只需关注抽象接口,无需了解具体实现。

最终结论 :桥接模式通过组合将对外接口类与实现类解耦,但其本质是支持抽象与实现的独立扩展,而非单纯的组合关系。组合是实现解耦的关键手段,但需结合独立变化的需求判断是否适用。

相关推荐
老当益壮梁奶奶1 小时前
Linux软件编程学习笔记(二)Linux文件IO编程入门:从fopen到fgetc
linux·c语言·c++·笔记·学习
sunoo-2291 小时前
C 语言文件 IO 全攻略:从基础函数到实战踩坑(BMP 读取 + 词典查询)
linux·c语言·前端·笔记·vscode·学习
蒸蒸yyyyzwd2 小时前
cpp选手秋招学习笔记 day12
笔记·学习·oracle
Wang's Blog2 小时前
PostgreSQL笔记38:慢查询定位与优化的系统方法论
数据库·笔记·postgresql
XiaQ09192 小时前
Linux 常用命令学习笔记(用户管理篇):用户、组与权限的钥匙
linux·开发语言·笔记·学习
He BianGu2 小时前
【笔记】使用Assembly.LoadFrom和AssemblyLoadContext加载插件对比,以及有没有更合适的加载插件方案
笔记
hhwyqwqhhwy2 小时前
正点原子-ZYNQ7020 开发笔记
笔记
LuminousCPP2 小时前
栈和队列专题(四):LeetCode 232. 用栈实现队列|双栈分工 + 按需迁移 + 摊还 O(1)
c语言·数据结构·笔记·算法·leetcode
GGMM7892 小时前
富士 EP‑3957E‑C4 电源驱动板维修实战笔记
笔记·变频器·变频器维修
Wang's Blog3 小时前
PostgreSQL笔记37:数据库性能瓶颈排查方法论与工具链
数据库·笔记·postgresql