Bridge模式的核心是组合加抽象,通过将“抽象”(如Shape)与“实现”(如Renderer)解耦,使二者可独立变化;Shape持Renderer指针,运行时绑定,支持动态切换渲染器。

Bridge模式的核心不是继承,而是组合加抽象
桥接模式的关键在于把“抽象”和“实现”解耦,让两者可以独立变化。C++里最容易踩的坑是误用继承代替委托——比如写一个 Shape 类再派生 Circle、Rectangle,然后又在每个子类里硬编码渲染逻辑,这根本不是桥接,是紧耦合。
真正桥接需要两组平行的抽象:一组描述“做什么”(如 Shape),另一组描述“怎么做”(如 Renderer),前者持有一个指向后者的指针,运行时才绑定。
-
Shape及其子类不关心具体怎么画,只调用renderer->render() -
Renderer是纯虚接口,由OpenGLRenderer、SVGRenderer等具体实现 - 构造
Circle时传入任意Renderer*,后续可随时替换(比如从控制台渲染切到图形窗口)
如何定义抽象接口与具体实现类
抽象层要足够稳定,避免频繁修改;实现层可以自由增删,不影响上层。典型错误是把 render() 的参数设计成具体类型(如 int x, int y, int radius),导致每次新增图形都要改 Renderer 接口。
更合理的方式是让 Renderer 接口只暴露通用操作,把细节交给 Shape 子类自行解释:
立即学习“C++免费学习笔记(深入)”;
class Renderer {
public:
virtual ~Renderer() = default;
virtual void render_circle(float x, float y, float radius) = 0;
virtual void render_rectangle(float x, float y, float width, float height) = 0;
};
<p>class OpenGLRenderer : public Renderer {
public:
void render_circle(float x, float y, float radius) override {
// glDrawArrays...
}
void render_rectangle(...) override { /<em> ... </em>/ }
};
注意:不要在 Renderer 中添加 set_color() 或 set_line_width() 这类状态方法——那属于另一个维度的抽象,应另起一个 Style 接口桥接。
Shape 构造时传入 Renderer 指针,而非在函数里 new
常见错误是让 Shape::draw() 内部自己创建 new OpenGLRenderer,这破坏了桥接的灵活性,也造成内存管理混乱。
- 必须由上层控制生命周期:谁 new,谁 delete(或改用
std::unique_ptr<renderer></renderer>) - 推荐构造函数传参:
Circle::Circle(Renderer* r) : renderer_(r) {} - 如果允许运行时切换,提供
set_renderer(Renderer* r),但需确保旧 renderer 不被意外 delete - 避免裸指针悬空:若
Renderer生命周期短于Shape,必须用弱引用或观察者机制,否则 crash
为什么不用模板替代虚函数?
有人会想:用模板参数 template<typename R> 替代 Renderer*,编译期绑定,性能更好。但这不是桥接,是策略模式(Strategy)的变体。
桥接强调“运行时可变”,核心价值在于动态适配不同环境(比如加载插件式渲染器、根据配置切换 SVG/Canvas 输出)。模板方案会导致每种 Shape<R1>、Shape<R2> 成为完全不同的类型,无法放入同一容器:
// ❌ 模板方案无法统一管理 std::vector<std::unique_ptr<Shape<OpenGLRenderer>>> v1; std::vector<std::unique_ptr<Shape<SVGRenderer>>> v2; // 类型不兼容 <p>// ✅ 虚函数方案天然支持多态容器 std::vector<std::unique_ptr<Shape>> shapes; shapes.push_back(std::make_unique<Circle>(new OpenGLRenderer)); shapes.push_back(std::make_unique<Rectangle>(new SVGRenderer));
桥接不是为了省虚函数开销,而是为了隔离变化维度。虚表那点成本,在图形渲染这种场景里几乎可以忽略。


















