7. 桥接模式(Bridge)

问题:一个类有多个维度的变化(如形状×颜色),用继承会导致子类爆炸。

核心:把不同维度拆成独立层级,通过组合而非继承连接。

interface Color {
  apply(): string;
}

// 颜色维度
class Red implements Color  { apply(): string { return '红色'; } }
class Blue implements Color { apply(): string { return '蓝色'; } }

// 形状维度(持有颜色的引用)
class Shape {
  constructor(protected color: Color) {}
}
class Circle extends Shape {
  draw(): string { return `${this.color.apply()}圆形`; }
}
class Square extends Shape {
  draw(): string { return `${this.color.apply()}方形`; }
}

console.log(new Circle(new Blue()).draw());  // 蓝色圆形
console.log(new Square(new Red()).draw());   // 红色方形
package bridge

import "fmt"

// 颜色维度
type Color interface{ Apply() string }

type Red struct{}
func (r Red) Apply() string { return "红色" }

type Blue struct{}
func (b Blue) Apply() string { return "蓝色" }

// 形状维度
type Shape struct{ Color Color }

func (s Shape) Draw() string { return "" }

type Circle struct{ Shape }
func (c Circle) Draw() string {
  return fmt.Sprintf("%s圆形", c.Color.Apply())
}

type Square struct{ Shape }
func (s Square) Draw() string {
  return fmt.Sprintf("%s方形", s.Color.Apply())
}

实战场景

  • UI 控件和渲染平台分离:同一个 Button、Modal、Toast 可以桥接到 Web、Native、Canvas 或终端输出。
  • 图形和颜色分离:形状是一条变化线,颜色、描边、填充样式是另一条变化线,组合比继承更可控。
  • 消息内容和发送渠道分离:告警、验证码、营销消息是一组抽象,邮件、短信、Push、Webhook 是另一组实现。
  • 存储抽象和存储后端分离:业务只关心文件存取,后端可以是本地磁盘、S3、R2、OSS 或内存存储。
  • 报表类型和输出格式分离:销售报表、库存报表、用户报表可以分别输出成 HTML、PDF、Excel、CSV。
  • 设备控制和通信协议分离:智能家居里的灯、空调、门锁与 Wi-Fi、蓝牙、Zigbee 协议可以独立演进。
  • 数据访问和缓存策略分离:Repository 负责业务查询,缓存实现可以切换为内存、Redis、CDN 或无缓存。
  • 日志内容和输出目的地分离:同一条日志可以输出到控制台、文件、远程采集器或测试缓冲区。
  • 游戏角色和技能实现分离:角色类型、武器、移动方式、渲染风格分别变化时,用桥接避免组合爆炸。
  • 多品牌 SaaS:业务页面结构相同,但品牌主题、文案策略、组件实现不同,可以把品牌实现作为桥接的一端。