桥接模式的核心是使抽象与实现分离并独立变化,通过组合(如std::unique_ptr)而非继承连接二者;implementor仅封装平台相关操作,严禁混入业务逻辑或反向依赖,接口粒度需精细以支持灵活扩展与测试。

桥接模式不是“加个接口就完事”
桥接模式的核心目标是让抽象(Abstraction)和实现(Implementor)能独立变化,而不是把二者硬绑在继承树里。很多人一上来就写个基类+虚函数,结果发现新增一个平台(比如从 Windows 切到 Linux)还得改抽象层逻辑——这说明没真正桥接,只是多态的滥用。
关键判断:如果 Abstraction 类中频繁出现 if (platform == Windows) {...} 或需要为每个实现变体重复定义相似接口,那当前结构已经违背桥接初衷。
std::unique_ptr<implementor></implementor> 比裸指针更安全也更常见
桥接依赖运行时绑定,但裸指针(Implementor*)容易引发空解引用、资源泄漏或所有权混乱。现代 C++ 工程中,std::unique_ptr<implementor></implementor> 是更稳妥的选择。
- 构造时传入具体实现,例如
ConcreteAbstraction(std::make_unique<windowsrenderer>())</windowsrenderer> - 避免在
Abstraction中暴露setImpl()这类可变接口——除非业务明确要求运行时切换实现(如热更新渲染后端) - 若需共享实现(比如多个窗口共用一个 OpenGL 上下文),改用
std::shared_ptr<implementor></implementor>,但要警惕循环引用
示例片段:
class Abstraction {
protected:
std::unique_ptr<implementor> impl_;
public:
explicit Abstraction(std::unique_ptr<implementor> impl) : impl_(std::move(impl)) {}
virtual void operation() = 0;
};</implementor></implementor>
别在 Implementor 接口里塞平台无关逻辑
Implementor 的职责必须严格限定为“平台/技术栈相关操作”。一旦你在 OpenGLRenderer::drawRect() 里开始做坐标归一化、图层合并或状态缓存,就模糊了抽象与实现的边界——这些该由上层 Abstraction 或其子类处理。
常见错误现象:
-
Implementor子类之间大量重复代码(比如所有渲染器都自己实现纹理加载逻辑)→ 应抽成独立服务,由Abstraction注入 -
Implementor需要访问Abstraction的成员变量 → 反向依赖,破坏桥接结构;应通过参数传递必要数据 - 为兼容旧版 API,在
Implementor中加条件编译(#ifdef WIN32)→ 说明抽象层没隔离好差异,应拆出更细粒度的Implementor子类
大型工程中桥接常和 PIMPL、策略模式混用
真实项目不会只靠桥接“一招鲜”。比如 Qt 的 QPainter 是桥接(后端是 QPaintEngine),但它内部又用 PIMPL 隐藏了引擎细节;而像日志模块可能把“输出目标”作为桥接的 Implementor,再把“格式化策略”作为另一个策略对象注入。
此时要注意:
- 桥接的
Implementor接口粒度要足够小,否则策略对象无法灵活组合 - 避免多层桥接嵌套(如
Abstraction → Bridge1 → Bridge2 → Implementor),调试和性能追踪会迅速失控 - 构建系统需确保各
Implementor实现(如VulkanRenderer.cpp、DirectX12Renderer.cpp)按需编译,不能因引入一个平台实现导致全量重编
最容易被忽略的一点:桥接之后,单元测试得分别覆盖 Abstraction 行为和每个 Implementor 的契约。光测 Abstraction 走通流程,不代表 VulkanRenderer 真能正确提交 draw call。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











