桥接模式(Bridge Pattern)
桥接模式是结构型设计模式的重要成员,其核心目标是将抽象部分与实现部分分离,使它们可以独立地变化。它如同现实中的 “电视遥控器”—— 遥控器(抽象部分)与电视(实现部分)通过无线信号(桥接)连接,不同品牌的遥控器可控制不同品牌的电视,两者的升级迭代互不影响。
一、桥接模式核心概念(通用)
1. 定义
将抽象部分与它的实现部分分离,使它们都可以独立地变化。这里的 “抽象” 指抽象类 / 接口,“实现” 指具体实现类,“分离” 指通过组合而非继承建立关联,形成一座 “桥” 连接两者。
2. 意图
- 解决多维度变化问题:当一个类存在两个或多个独立变化的维度(如 “形状” 和 “颜色”、“操作系统” 和 “软件”),避免使用多层继承导致的类爆炸。
- 实现抽象与实现的解耦:抽象部分(如遥控器)不依赖具体实现(如电视),而是通过接口依赖,使两者可独立扩展。
- 遵循 “开闭原则”:新增抽象或实现时,无需修改原有代码,只需添加新类。
3. 通用核心组件
桥接模式的核心是通过 “抽象 - 实现” 的分离与桥接,包含 4 个核心角色:
| 角色名称 | 职责描述 |
|---|---|
| Abstraction(抽象化角色) | 定义抽象类的接口,持有一个对 “实现化角色” 的引用(桥接的核心),通过该引用调用实现化角色的方法。 |
| RefinedAbstraction(扩展抽象化角色) | 继承 Abstraction,对其接口进行扩展,实现更具体的业务逻辑,但仍通过 Abstraction 持有的引用调用实现化角色的方法。 |
| Implementor(实现化角色) | 定义实现类的接口,供 Abstraction 调用,与 Abstraction 的接口可以不同(体现分离)。 |
| ConcreteImplementor(具体实现化角色) | 实现 Implementor 接口,提供具体的实现逻辑。 |
二、桥接模式详细解析(以 “形状与颜色” 为例)
以 “绘制不同颜色的形状” 为场景:形状(圆形、矩形)和颜色(红色、蓝色)是两个独立变化的维度。若用继承实现,需定义RedCircle、BlueCircle、RedRectangle、BlueRectangle等类(类数量 = 形状数 × 颜色数),扩展性极差。桥接模式通过分离 “形状”(抽象)和 “颜色”(实现),使两者独立扩展。
1. 结构
- Implementor(实现化角色):
Color,定义颜色的接口(applyColor())。 - ConcreteImplementor(具体实现化角色):
Red、Blue,实现applyColor()(具体颜色逻辑)。 - Abstraction(抽象化角色):
Shape,持有Color引用,定义抽象方法draw()(绘制形状),内部调用color.applyColor()。 - RefinedAbstraction(扩展抽象化角色):
Circle、Rectangle,继承Shape,实现draw()(具体形状绘制)。
2. 类图(Mermaid)

classDiagram
%% 实现化角色:颜色接口(定义实现部分的规范)
class Color {
<<Interface>>
+applyColor(): void // 应用颜色的方法
}
%% 具体实现化角色:红色和蓝色
class Red {
+applyColor(): void // 具体实现:应用红色
}
class Blue {
+applyColor(): void // 具体实现:应用蓝色
}
%% 抽象化角色:形状(持有Color引用,桥接的核心)
class Shape {
<<Abstract>>
-color: Color // 持有实现化角色的引用(桥)
+Shape(color: Color) // 构造注入Color
+abstract draw(): void // 抽象方法:绘制形状
}
%% 扩展抽象化角色:圆形和矩形
class Circle {
+draw(): void // 实现:绘制圆形,调用color.applyColor()
}
class Rectangle {
+draw(): void // 实现:绘制矩形,调用color.applyColor()
}
%% 关系:实现化与具体实现
Color <|-- Red
Color <|-- Blue
%% 关系:抽象化与扩展抽象化
Shape <|-- Circle
Shape <|-- Rectangle
%% 核心桥接关系:抽象化持有实现化的引用
Shape o-- Color : 持有(桥接)
3. 时序图(Mermaid)
以 “绘制红色圆形” 为例,展示桥接模式的调用流程:
sequenceDiagram
participant Client(客户端)
participant Red(具体实现:红色)
participant Shape(抽象化:形状)
participant Circle(扩展抽象:圆形)
%% 1. 客户端创建具体实现(红色)和扩展抽象(圆形,传入红色)
Client->>Red: new Red()
Client->>Circle: new Circle(red) // 桥接:圆形持有红色引用
Circle->>Shape: 调用父类构造器,传入red
Shape-->>Circle: 初始化完成
%% 2. 客户端调用圆形的draw()方法
Client->>Circle: draw()(绘制圆形)
%% 3. 圆形的draw()调用抽象化角色的color引用(红色)
Circle->>Shape: 获取color引用(red)
Shape-->>Circle: 返回red
%% 4. 圆形调用红色的applyColor()
Circle->>Red: applyColor()(应用红色)
Red-->>Circle: 完成颜色应用
%% 5. 圆形完成自身绘制逻辑
Circle-->>Client: 输出“绘制红色圆形”
4. 优点
- 解决类爆炸问题:当存在两个独立维度时,类数量从 “维度 A 数量 × 维度 B 数量” 减少为 “维度 A 数量 + 维度 B 数量”(如形状 2 种 × 颜色 2 种,从 4 类减为 4 类?不,新增 1 种形状或颜色时,只需加 1 类,而非加 N 类)。
- 抽象与实现解耦:抽象部分(形状)和实现部分(颜色)通过接口关联,互不依赖,可独立扩展(新增形状无需改颜色,新增颜色无需改形状)。
- 符合开闭原则:扩展新的抽象或实现时,无需修改原有代码,只需新增类(如新增 “绿色” 只需加
Green类,新增 “三角形” 只需加Triangle类)。 - 提高灵活性:运行时可动态切换实现(如圆形可动态从红色切换为蓝色)。
5. 缺点
- 增加系统复杂度:需拆分出 “抽象” 和 “实现” 两个独立层次,理解难度提高(相比直接继承)。
- 设计要求高:需准确识别系统中两个独立变化的维度,若维度划分不合理,会导致模式应用失效。
- 可能过度设计:若系统不存在多维度变化,使用桥接模式会增加不必要的抽象层。
三、Java 代码实现(形状与颜色示例)
1. 实现化角色(Color 接口)
定义颜色的实现接口,供抽象化角色调用:
// 实现化角色:颜色接口
public interface Color {
// 应用颜色(具体实现由子类完成)
void applyColor();
}
2. 具体实现化角色(Red、Blue)
实现颜色接口,提供具体颜色逻辑:
// 具体实现化角色:红色
public class Red implements Color {
@Override
public void applyColor() {
System.out.print("红色");
}
}
// 具体实现化角色:蓝色
public class Blue implements Color {
@Override
public void applyColor() {
System.out.print("蓝色");
}
}
3. 抽象化角色(Shape 抽象类)
持有 Color 引用(桥接核心),定义抽象绘制方法:
// 抽象化角色:形状
public abstract class Shape {
// 持有实现化角色的引用(桥)
protected Color color;
// 构造器注入Color,建立桥接
public Shape(Color color) {
this.color = color;
}
// 抽象方法:绘制形状(由子类实现具体逻辑)
public abstract void draw();
}
4. 扩展抽象化角色(Circle、Rectangle)
继承 Shape,实现具体形状的绘制,调用 Color 的方法:
// 扩展抽象化角色:圆形
public class Circle extends Shape {
public Circle(Color color) {
super(color);
}
@Override
public void draw() {
System.out.print("绘制");
color.applyColor(); // 调用实现化角色的方法(桥接调用)
System.out.println("圆形");
}
}
// 扩展抽象化角色:矩形
public class Rectangle extends Shape {
public Rectangle(Color color) {
super(color);
}
@Override
public void draw() {
System.out.print("绘制");
color.applyColor(); // 调用实现化角色的方法(桥接调用)
System.out.println("矩形");
}
}
5. 客户端(Client)
通过桥接组合不同的抽象与实现,无需关心内部关联:
// 客户端
public class Client {
public static void main(String[] args) {
// 1. 红色圆形(桥接:圆形+红色)
Shape redCircle = new Circle(new Red());
redCircle.draw(); // 输出:绘制红色圆形
// 2. 蓝色矩形(桥接:矩形+蓝色)
Shape blueRectangle = new Rectangle(new Blue());
blueRectangle.draw(); // 输出:绘制蓝色矩形
// 3. 动态切换颜色(红色矩形)
Shape redRectangle = new Rectangle(new Red());
redRectangle.draw(); // 输出:绘制红色矩形
}
}
6. 输出结果
绘制红色圆形
绘制蓝色矩形
绘制红色矩形
四、适用环境
桥接模式适用于以下场景,核心判断标准是 “系统存在两个或多个独立变化的维度,且需要独立扩展”:
- 多维度变化场景:类存在两个或多个独立变化的维度(如 “产品类型” 和 “品牌”、“操作系统” 和 “应用程序”),且每个维度都可能扩展。
- 避免多层继承:当使用继承会导致类数量急剧增加(类爆炸)时,如 “形状 × 颜色” 若用继承,每新增 1 种形状或颜色需新增 N 个类。
- 抽象与实现需独立扩展:抽象部分和实现部分需分别由不同的团队开发,或需在运行时动态切换实现。
- 希望隐藏实现细节:客户端只需依赖抽象接口,无需知道具体实现(如遥控器无需知道电视的内部原理)。
五、模式分析
1. 核心本质
桥接模式的本质是 “分离抽象与实现,通过组合建立桥接,实现独立扩展”:
- 分离:将抽象(如形状)和实现(如颜色)拆分为两个独立的继承体系。
- 桥接:抽象部分通过持有实现部分的引用(而非继承)建立关联,形成 “桥”。
- 独立扩展:两个体系可各自扩展(新增形状或颜色),互不影响。
2. 与其他模式的区别
| 模式 | 核心差异 | 典型场景 |
|---|---|---|
| 桥接模式 | 分离两个独立维度,通过组合桥接,解决类爆炸 | 形状 + 颜色、遥控器 + 电视 |
| 适配器模式 | 解决接口不兼容问题,使现有类能被复用 | 旧系统接口适配新系统 |
| 装饰器模式 | 不改变接口,动态为对象添加功能 | 给组件添加日志、缓存功能 |
| 策略模式 | 封装算法家族,使算法可动态替换 | 排序算法、支付方式选择 |
六、模式扩展
桥接模式可根据维度数量和关联方式扩展:
1. 多维度桥接
当系统存在 3 个或更多独立维度时(如 “形状 + 颜色 + 边框”),可通过多层桥接实现:
- 第一层:形状持有颜色引用;
- 第二层:颜色持有边框引用;
- 客户端通过形状间接调用颜色和边框的方法。
2. 动态切换实现
抽象化角色可提供setImplementor()方法,允许运行时动态更换实现(如圆形从红色切换为蓝色):
public abstract class Shape {
protected Color color;
public void setColor(Color color) { // 动态切换实现
this.color = color;
}
// ...其他代码
}
3. 结合工厂模式
通过工厂模式创建抽象化和实现化对象,降低客户端与具体类的耦合:
// 形状工厂
public class ShapeFactory {
public static Shape createCircle(Color color) {
return new Circle(color);
}
}
七、模式应用(通用 + Android)
1. 通用领域应用
- 跨平台 UI 框架:如 “按钮(抽象)” 与 “Windows 按钮实现 / Linux 按钮实现(实现)”,按钮逻辑与系统底层实现分离,可独立扩展。
- 数据库驱动:“数据库操作接口(抽象)” 与 “MySQL 驱动 / Oracle 驱动(实现)”,操作逻辑与具体数据库实现分离。
- 消息系统:“消息发送器(抽象)” 与 “短信发送 / 邮件发送 / 推送发送(实现)”,发送逻辑与具体渠道实现分离。
2. Android 中的应用
Android 框架中大量使用桥接模式分离 “抽象逻辑” 与 “平台实现”:
(1)View 与 Drawable(UI 绘制)
- 角色对应:
View:抽象化角色(定义 UI 组件的抽象接口,如draw());- 具体 View(
TextView/ImageView):扩展抽象化角色(实现具体 UI 逻辑); Drawable:实现化角色(定义绘制逻辑的接口,如draw(Canvas));- 具体 Drawable(
BitmapDrawable/ColorDrawable):具体实现化角色(提供具体绘制能力)。
- 桥接逻辑:
View通过setBackground(Drawable)持有Drawable引用,View.draw()调用Drawable.draw()完成背景绘制,两者独立扩展(新增 View 无需改 Drawable,新增 Drawable 可被所有 View 使用)。
// 示例:TextView(扩展抽象)使用ColorDrawable(具体实现)
TextView textView = new TextView(context);
Drawable redDrawable = new ColorDrawable(Color.RED); // 具体实现
textView.setBackground(redDrawable); // 桥接:View持有Drawable引用
(2)Window 与 WindowManager(窗口管理)
- 角色对应:
Window:抽象化角色(定义窗口的抽象接口,如addView());PhoneWindow:扩展抽象化角色(Android 中Window的唯一实现);WindowManager:实现化角色(定义窗口管理的接口,如addView());WindowManagerImpl:具体实现化角色(实现窗口的底层管理)。
- 桥接逻辑:
PhoneWindow持有WindowManager引用,通过它调用底层窗口管理功能,Window的抽象逻辑与WindowManager的平台实现分离。
(3)MediaPlayer 与 MediaPlayerService(媒体播放)
- 角色对应:
MediaPlayer:抽象化角色(定义媒体播放接口,如start()/pause());MediaPlayerService:实现化角色(定义底层播放服务接口);- 具体服务实现:
StagefrightPlayer等(具体实现化角色)。
- 桥接逻辑:
MediaPlayer通过 Binder 机制与MediaPlayerService通信,上层播放逻辑与底层解码实现分离,支持不同格式的播放服务扩展。
八、总结
桥接模式是处理 “多维度变化” 问题的核心方案,其核心价值在于 “分离与桥接”:
- 核心优势:解决类爆炸问题,使抽象与实现独立扩展,提高系统灵活性和可维护性。
- 适用场景:存在两个或多个独立变化的维度,且需要避免多层继承的场景(如 UI 组件与绘制实现、跨平台功能等)。
- 实践建议:
- 准确识别系统中的独立维度(如 “功能” 与 “平台”、“类型” 与 “实现”);
- 优先通过组合而非继承建立关联(抽象持有实现引用);
- 结合工厂模式降低客户端与具体类的耦合。
桥接模式不仅是一种设计技巧,更是一种 “拆分复杂系统” 的思维 —— 通过识别独立变化的部分,建立松耦合的关联,使系统在扩展时保持简洁与灵活。