Skip to content

桥接模式(Bridge Pattern) ​

一句话记忆口诀:桥接分离抽象与实现两个独立变化的维度,用组合替代继承,避免笛卡尔积式的类爆炸。

1. 🏠 生活类比 ​

遥控器和电视机是两个独立的东西。遥控器有基础版和高级版,电视有索尼和三星。两个维度自由组合:

  • 基础遥控器 + 索尼电视
  • 高级遥控器 + 索尼电视
  • 基础遥控器 + 三星电视
  • 高级遥控器 + 三星电视

如果用继承:BasicSonyRemote、AdvancedSonyRemote、BasicSamsungRemote、AdvancedSamsungRemote — 4 个类。新增一个 LG 电视?再加 2 个类!

桥接模式的做法:遥控器持有电视的引用(组合),两个维度独立变化。

2. 💩 烂代码:继承导致类爆炸 ​

java
// 形状 × 颜色 = 类爆炸
// 2 种形状 × 3 种颜色 = 6 个类
class RedCircle extends Circle {
    public void draw() { drawCircle(); fillRed(); }
}
class BlueCircle extends Circle {
    public void draw() { drawCircle(); fillBlue(); }
}
class GreenCircle extends Circle {
    public void draw() { drawCircle(); fillGreen(); }
}
class RedRectangle extends Rectangle {
    public void draw() { drawRectangle(); fillRed(); }
}
class BlueRectangle extends Rectangle {
    public void draw() { drawRectangle(); fillBlue(); }
}
class GreenRectangle extends Rectangle {
    public void draw() { drawRectangle(); fillGreen(); }
}
// 新增一种颜色?所有形状都要新增子类!
// 新增一种形状?所有颜色都要新增子类!
// N 种形状 × M 种颜色 = N×M 个子类

问题根因:多个独立变化的维度通过继承耦合,子类数量呈笛卡尔积增长。

3. ✨ 桥接模式方案 ​

将"形状"和"颜色"分离为两个独立维度,通过组合连接:

4. 💻 完整代码实现 ​

java
// ===== 实现维度:颜色接口 =====
public interface Color {
    String fill();
}

public class Red implements Color {
    @Override
    public String fill() { return "红色"; }
}

public class Blue implements Color {
    @Override
    public String fill() { return "蓝色"; }
}

public class Green implements Color {
    @Override
    public String fill() { return "绿色"; }
}

// ===== 抽象维度:形状 =====
public abstract class Shape {
    protected final Color color; // 桥接:持有实现维度的引用

    public Shape(Color color) {
        this.color = color;
    }

    public abstract void draw();
}

public class Circle extends Shape {
    private final double radius;

    public Circle(double radius, Color color) {
        super(color);
        this.radius = radius;
    }

    @Override
    public void draw() {
        System.out.println("绘制" + color.fill() + "圆形,半径=" + radius);
    }
}

public class Rectangle extends Shape {
    private final double width;
    private final double height;

    public Rectangle(double width, double height, Color color) {
        super(color);
        this.width = width;
        this.height = height;
    }

    @Override
    public void draw() {
        System.out.println("绘制" + color.fill() + "矩形,宽=" + width + ",高=" + height);
    }
}

// ===== 使用示例 =====
public class Main {
    public static void main(String[] args) {
        // 两个维度自由组合
        Shape redCircle = new Circle(5.0, new Red());
        Shape blueCircle = new Circle(3.0, new Blue());
        Shape greenRect = new Rectangle(4.0, 6.0, new Green());

        redCircle.draw();    // 绘制红色圆形,半径=5.0
        blueCircle.draw();   // 绘制蓝色圆形,半径=3.0
        greenRect.draw();    // 绘制绿色矩形,宽=4.0,高=6.0

        // 新增黄色?只需新增 Yellow 类,不影响任何 Shape 子类!
        // 新增三角形?只需新增 Triangle 类,不影响任何 Color 实现!
    }
}

4.1 进阶示例:多渠道通知系统 ​

java
// ===== 实现维度:消息发送渠道 =====
public interface MessageSender {
    void send(String title, String content);
}

public class EmailSender implements MessageSender {
    @Override
    public void send(String title, String content) {
        System.out.println("[邮件] " + title + ": " + content);
    }
}

public class SmsSender implements MessageSender {
    @Override
    public void send(String title, String content) {
        System.out.println("[短信] " + title + ": " + content);
    }
}

public class DingTalkSender implements MessageSender {
    @Override
    public void send(String title, String content) {
        System.out.println("[钉钉] " + title + ": " + content);
    }
}

// ===== 抽象维度:消息类型 =====
public abstract class Message {
    protected final MessageSender sender; // 桥接

    public Message(MessageSender sender) {
        this.sender = sender;
    }

    public abstract void send(String content);
}

public class NormalMessage extends Message {
    public NormalMessage(MessageSender sender) { super(sender); }

    @Override
    public void send(String content) {
        sender.send("普通通知", content);
    }
}

public class UrgentMessage extends Message {
    public UrgentMessage(MessageSender sender) { super(sender); }

    @Override
    public void send(String content) {
        sender.send("【紧急】", content + " 请及时处理!");
    }
}

// ===== 使用 =====
Message urgentEmail = new UrgentMessage(new EmailSender());
urgentEmail.send("服务器宕机"); // [邮件] 【紧急】: 服务器宕机 请及时处理!

Message normalDingTalk = new NormalMessage(new DingTalkSender());
normalDingTalk.send("日报已提交"); // [钉钉] 普通通知: 日报已提交

5. 🔧 框架应用 ​

框架/类抽象维度实现维度桥接程度判定依据
JDBC Driver/ConnectionJDBC 统一访问抽象厂商驱动对 JDBC 契约的实现典型应用通过 JDBC 契约访问数据库,SQL 与数据类型兼容时新增或替换驱动通常不改访问代码
SLF4J + Logback日志门面(SLF4J)日志实现(Logback/Log4j)近似门面与实现可替换,但主要体现门面模式,两个维度独立演化不明显
Spring ResourceResource 接口ClassPath/FileSystem/URL近似体现统一资源抽象与多种实现的分离,但未必具备两个独立扩展层次的完整结构
PlatformTransactionManager事务管理 APIJDBC/JPA/JTA 实现近似抽象与实现分离,但主要体现为策略选择,独立演化不明显
java.util.ListList 接口ArrayList/LinkedList结构相似只有接口与实现类的多态,单一变化维度,不构成桥接

桥接的关键是两个维度独立演化,而不是只要存在接口和实现类。上表「近似」和「结构相似」的条目常被误归为桥接,实际更接近策略模式或单纯的多态。

6. ⚠️ 适用场景 ​

适合使用桥接模式的情况:

  • 一个类存在两个或多个独立变化的维度
  • 不希望因维度组合导致类数量爆炸
  • 需要让抽象层与实现层独立演化,部分场景还需要在运行期选择或切换实现

不适合的情况:

  • 只有一个主要变化维度,且不存在需要分离的第二个维度 → 不必引入桥接,可按变化方式选择继承、组合或策略模式
  • 两个维度高度依赖同一套变化规则,无法形成有意义的独立抽象 → 拆分收益可能不足以抵消额外复杂度
  • 组合数量少、变化稳定,且组合类的维护成本低于引入两层抽象的成本 → 直接继承更简单

7. 🔍 桥接模式 vs 策略模式 ​

对比维度桥接模式策略模式
设计意图分离两个独立变化维度的耦合封装并替换一组算法或行为
维度通常两个独立变化的维度通常一个维度(算法选择)
关系抽象层持有实现层引用,双方可沿各自层次扩展Context 持有 Strategy,调用方可替换具体策略
典型场景JDBC 驱动、跨平台 UI支付方式、排序算法

两者结构相似,关键区别在设计意图而非维度数量。桥接侧重解开两个变化维度之间的耦合,策略侧重算法的可替换性;两种意图可以在同一设计中同时存在,不必强行二选一。

Released under the MIT License.