为何用Multiple Inheritance实现Bridge Pattern?该实现为何非真正桥接?
多重继承实现桥接模式的意义、矛盾点与本质区别
一、用多重继承实现桥接模式的表面“意义”
有人尝试用多重继承实现桥接,无非是想省掉抽象类对实现类的委托代码——直接让抽象类同时继承抽象基类和实现类,看起来能一步到位把抽象和实现的功能合并。但这种做法完全是对桥接模式设计意图的误解,本质是用继承的硬耦合替代了组合的松耦合。
二、与GoF《设计模式》解释的矛盾
GoF对桥接模式的核心定义非常明确:
将抽象部分与实现部分分离,使它们都可以独立地变化。
桥接模式的诞生就是为了解决继承层次膨胀的问题——当抽象和实现都有多个维度的变化时,用继承会导致类数量呈指数级增长(比如有2种抽象、3种实现,继承需要6个类;桥接只需要2+3=5个类,维度越多差距越大)。而多重继承恰恰是把抽象和实现绑定在一起,一旦抽象或实现需要扩展,必须新增继承组合的类,完全违背了“独立变化”的核心意图。
三、为什么多重继承实现不是真正的桥接模式
核心原因有三点:
- 耦合度极高:抽象和实现通过继承绑定,修改实现类可能直接影响抽象类,反之亦然,无法独立演化。
- 违反开闭原则:新增一种抽象或实现时,必须创建新的多重继承类,而不是单独新增抽象或实现类,类的数量会快速膨胀。
- 潜在的菱形继承问题:如果抽象和实现类有共同的基类,会引发继承歧义,大幅增加维护复杂度。
四、示例对比
1. 真正的桥接模式实现(组合方式)
假设我们有“形状”抽象维度,“渲染方式”实现维度:
// 实现层:渲染方式 class Renderer { public: virtual void renderCircle(float radius) = 0; }; class OpenGLRenderer : public Renderer { public: void renderCircle(float radius) override { // OpenGL渲染逻辑:比如输出"用OpenGL画半径为X的圆" } }; class DirectXRenderer : public Renderer { public: void renderCircle(float radius) override { // DirectX渲染逻辑:比如输出"用DirectX画半径为X的圆" } }; // 抽象层:形状 class Shape { protected: Renderer* renderer; // 组合实现类,而非继承 public: Shape(Renderer* r) : renderer(r) {} virtual void draw() = 0; }; class Circle : public Shape { private: float radius; public: Circle(float r, Renderer* renderer) : Shape(renderer), radius(r) {} void draw() override { renderer->renderCircle(radius); } };
如果要新增“正方形”抽象,只需要新增Square类;新增“VulkanRenderer”实现,只需要新增VulkanRenderer类,两个维度完全独立扩展。
2. 多重继承的错误实现
// 实现层:渲染方式 class OpenGLRenderer { public: void renderCircle(float radius) { // OpenGL渲染逻辑 } }; class DirectXRenderer { public: void renderCircle(float radius) { // DirectX渲染逻辑 } }; // 抽象基类 class ShapeBase { protected: float size; public: ShapeBase(float s) : size(s) {} virtual void draw() = 0; }; // 抽象+实现的多重继承绑定 class OpenGLCircle : public ShapeBase, public OpenGLRenderer { public: OpenGLCircle(float r) : ShapeBase(r) {} void draw() override { renderCircle(size); } }; class DirectXCircle : public ShapeBase, public DirectXRenderer { public: DirectXCircle(float r) : ShapeBase(r) {} void draw() override { renderCircle(size); } };
此时如果要新增Square抽象,必须同时创建OpenGLSquare、DirectXSquare;新增VulkanRenderer,又要创建VulkanCircle、VulkanSquare——类数量直接爆炸,而且抽象和实现完全绑定,无法单独修改渲染逻辑而不影响形状类。
内容的提问来源于stack exchange,提问作者BobDidley
相关产品推荐
相关产品推荐

