桥接模式解决什么
桥接模式(Bridge)把「做什么」与「怎么做」拆成两条独立的继承体系,再通过组合把它们关联起来。它要处理的典型困境是两个维度都在扩展:如果按维度相乘来派生子类,类型数量会迅速失控。把其中一个维度作为抽象层持有另一个维度的引用后,两侧可以各自演进,组合方式在运行时决定。
基本信息
| 意图 | 抽象与实现解耦,两条体系独立演化 |
|---|---|
| 典型信号 | 两个维度都在扩展,子类数量呈相乘关系 |
| 实现方式 | 抽象层持有一个实现层引用,调用时委托过去 |
| 与策略的差别 | 策略面向算法替换,桥接强调体系级的维度拆分 |
典型使用场景
- 图形与渲染后端:形状有圆形、矩形,渲染有矢量与位图,两个维度各自扩展而不是相乘
- 消息与发送渠道:消息类型与短信、邮件等通道分离,新增通道不影响消息类型
- 数据导出与文件格式:报表类型与输出格式两条体系,格式新增不必改报表类
- 跨平台界面控件:控件类型与平台实现分离,移植新平台只需增加实现层
- 设备驱动:设备能力与具体硬件实现分离,便于替换与模拟
结构示意
结构示意
// 维度一:抽象(做什么),持有维度二的引用
abstract class Shape {
protected final Renderer renderer; // 组合而非继承
Shape(Renderer r) { this.renderer = r; }
abstract void draw();
}
// 维度二:实现(怎么做),可独立扩展
interface Renderer { void renderCircle(); void renderSquare(); }与相邻模式对照
| 模式 | 关注点 | 分辨方式 |
|---|---|---|
| Bridge | 两个维度各自扩展 | 子类数量是否呈相乘关系 |
| Strategy | 单个算法族可替换 | 只有一条变化轴,替换发生在调用时 |
| Adapter | 接口不兼容的转换 | 目的是让既有类能配合使用,不是拆分维度 |
| Abstract Factory | 产品族的一致性 | 解决一组相关对象如何成套创建 |
| Decorator | 同一接口叠加行为 | 不新增维度,只在外层追加职责 |
只有一个维度存在扩展压力时不需要桥接:抽象层没有对应的变化来源,反而多出一层间接调用。判断依据是两侧是否都在持续新增类型。
拆成两条体系后要避免它们互相引用:若抽象层直接访问实现层的具体类型,或实现层反过来依赖抽象层的细节,解耦目标就落空了,改动又会沿着依赖链扩散。
落地检查清单
- 两个维度都能各自新增类型而不修改对方
- 抽象层只依赖实现层的接口,不依赖具体实现
- 新增一个维度取值时,改动局限在一条体系内
- 组合关系在运行时可以替换,便于测试与灰度