桥接模式的核心是组合而非继承,用于解耦抽象(如Shape)与实现(如Renderer)的独立扩展,避免子类爆炸,通过运行时注入实现类实现动态绑定。

桥接模式的核心不是继承而是组合
桥接模式要解决的问题很具体:当抽象(比如 Shape)和实现(比如 Renderer)都可能独立扩展时,用继承会爆炸式生成子类(CircleRaster、CircleVector、SquareRaster…),而桥接把二者解耦——抽象类持有一个实现类的引用,运行时动态绑定。
关键判断:如果你发现类名开始出现“XX+YY”式组合(如 RasterImage、VectorImage),且新增一种形状就要补全所有渲染方式,那就是桥接的典型信号。
- 抽象层(
Shape及其子类)不关心怎么画,只调用renderer.draw_circle()这类统一接口 - 实现层(
Renderer及其子类)不关心画什么,只提供基础绘图能力 - 两者通过构造函数注入关联,而非硬编码继承关系
如何定义抽象与实现的接口契约
接口设计决定桥接是否真正解耦。抽象端定义“做什么”,实现端定义“怎么做”,二者接口必须对齐但不能耦合。
常见错误是让 Shape 直接调用 renderer.rasterize() 或 renderer.to_svg() —— 这会让抽象层感知具体实现细节,违背桥接初衷。
立即学习“Python免费学习笔记(深入)”;
- 实现层接口应聚焦动作语义:
render_circle(x, y, radius)、render_square(x, y, size),而非技术名词 - 抽象层只暴露高层操作:
draw(),内部调用 renderer 的对应方法 - 如果实现类需要状态(如当前颜色),应在
Renderer基类中定义set_color(),而非让Shape操作renderer.color
Python 中避免过度设计的实用写法
Python 动态特性让桥接比 Java/C++ 更轻量,但容易误用成简单委托。真正需要桥接的场景是:抽象和实现都有多维度变化,且你预期未来会新增更多组合。
示例中若只有 RasterRenderer 和 VectorRenderer 两种实现,且短期内不会加新渲染方式,直接用策略模式更合适;只有当渲染器还要支持 WebGLRenderer、TextRenderer 等,且图形类型也要加 Triangle、Polygon 时,桥接的价值才凸显。
- 不必强求抽象基类和实现基类都带
ABC—— 如果只有两个具体实现,duck typing 足够 -
__init__(self, renderer)注入即可,无需工厂或配置中心 - 避免在
Shape中重复实现逻辑:比如Circle.draw()和Square.draw()都调self.renderer.render_XXX(),不要在每个子类里写不同参数计算
容易被忽略的运行时切换问题
桥接模式支持运行时更换实现,但实际使用中常被忽略这点。比如一个 Circle 实例初始化时用 RasterRenderer,后续想切到 VectorRenderer,必须确保 renderer 属性可写且线程安全(如果涉及并发)。
Python 默认允许重新赋值 shape.renderer = new_renderer,但要注意:旧 renderer 的状态(如缓存、上下文)不会自动迁移,新 renderer 可能需要重置。
- 如果 renderer 有内部状态(如当前坐标系、缩放因子),切换前需显式清理或同步
- 在 GUI 场景中,频繁切换 renderer 可能触发重绘,需考虑性能开销
- 单元测试时,用
unittest.mock.Mock()替换 renderer 更容易验证抽象层行为,而非依赖真实实现


















