← 返回题目列表

桥接模式如何解决多维度扩展导致的类爆炸?

高频 中等 第 6 / 25 题 更新于 2026/07/28
桥接模式类爆炸多维度扩展

简化版

桥接模式把多个变化维度从一条继承链中拆出来,通过组合关系连接。这样新增一个维度值只需要新增对应类,而不是为它和其他维度的每一种组合都创建子类。

详细版

类爆炸通常来自乘法组合。比如消息系统中有 3 种消息类型和 4 种发送渠道,如果用继承表达组合,可能需要 12 个类;以后增加 1 种消息类型,又要补 4 个类。

桥接模式会把它拆成:

  • 消息类型维度:NormalMessageUrgentMessageVerifyCodeMessage
  • 发送渠道维度:SmsSenderEmailSenderWeComSenderPushSender

消息类型通过 Sender 接口委托发送。新增消息类型只影响消息侧,新增发送渠道只影响渠道侧。

完整版教学

一、类爆炸的根源是维度相乘

单一维度扩展时,继承不一定有问题。例如只有图形类型变化,新增圆形、矩形、三角形,类数量大致是线性增长。

问题出现在两个维度同时变化:

维度 A维度 B继承组合数量
2 种3 种6 个类
4 种5 种20 个类
8 种6 种48 个类

随着维度增多,类数量会快速膨胀。更麻烦的是,很多类只是简单组合,没有真正新的业务价值。

二、继承方案为什么维护困难

假设用继承设计图形绘制:

Shape
├── SvgCircle
├── CanvasCircle
├── SvgRectangle
└── CanvasRectangle

如果新增 Triangle,要加 SvgTriangleCanvasTriangle。如果再新增 OpenGL 绘制方式,要为所有形状补一批 OpenGLXxx

这种设计有几个问题:

  • 类数量多,命名和目录都膨胀。
  • 相同逻辑在多个组合类中重复。
  • 新增一个维度值时要扫描另一个维度的所有已有值。
  • 修改公共规则时容易漏改某些组合类。

三、桥接模式如何拆维度

桥接方案会变成:

Shape 抽象侧
├── Circle
├── Rectangle
└── Triangle

Renderer 实现侧
├── SvgRenderer
├── CanvasRenderer
└── OpenGLRenderer

Shape 持有 Renderer

abstract class Shape {
    protected final Renderer renderer;

    protected Shape(Renderer renderer) {
        this.renderer = renderer;
    }

    public abstract void draw();
}

这样类数量从乘法关系变成加法关系。3 种形状和 3 种渲染方式不再需要 9 个组合类,而是 3 个形状类 + 3 个渲染类。

四、扩展成本如何下降

桥接模式下新增一个形状:

  • 新增一个 Shape 子类。
  • 复用所有已有 Renderer

新增一种渲染方式:

  • 新增一个 Renderer 实现类。
  • 复用所有已有 Shape

这就是开闭原则的体现:对扩展开放,对已有类修改关闭。

五、桥接不是减少所有类

桥接模式并不是让类数量永远最少。它有时会比简单写法多出接口和抽象类。

它真正减少的是组合类和重复代码。对于变化维度明确、组合关系复杂的系统,这个收益很明显;对于只有两三个固定组合的小功能,桥接可能显得过度设计。

六、判断是否存在多维度扩展

可以观察需求描述中的连接词:

  • “不同类型的 A 支持不同方式的 B”
  • “同一个业务能力要支持多个平台”
  • “同一种操作要输出多种格式”
  • “不同设备对应不同遥控器”

这些表达往往暗示两个维度:业务形态和实现方式。如果未来都可能扩展,就值得考虑桥接。

七、常见误区与追问

二维扩展的验收要同时观察类型数与修改面。初始2种通知×2种渠道,运行期有4种组合,但代码只维护4个具体类型;增加第3种通知后类型总数变5,不是6个组合子类。若增加一种通知仍要进入所有渠道类修改,说明维度边界泄漏。

检查维度判定依据
新增抽象成员只扩展抽象侧类型
新增实现成员只扩展 Implementor 侧类型
运行组合 3×2=6;核心具体类型 3+2=5

易错点:桥接减少的是组合类数量和修改传播,不是减少可用组合。

  • 误区:两个维度必须数量相同。 两侧数量彼此独立,任何抽象都可组合兼容实现。
  • 追问:如何限制不合法组合? 在工厂或能力声明中校验兼容矩阵,而不是把分支散到两侧。
  • 误区:新增维度成员完全零修改。 注册配置或工厂映射可能需要更新,但核心另一侧业务类型不应改。
  • 追问:能否支持运行期切换渠道? 若状态和线程安全允许,可替换 Implementor 或创建新 Abstraction。
  • 追问:第三个变化维度怎么办? 先评估是否真正正交,再组合新接口,避免对象装配失控。

八、加强记忆

桥接模式解决类爆炸的方式是把“乘法组合”改成“加法扩展”:继承会让 A × B 变成大量组合类,桥接让 A 和 B 各自成体系,再用组合把它们连起来。