设计模式-桥接模式

发布于:2025-06-20 ⋅ 阅读:(24) ⋅ 点赞:(0)

桥接模式

1. 核心思想:一句话点题

桥接模式的核心是:将抽象部分与它的实现部分分离,使它们都可以独立地变化。

这句话听起来很官方,我们把它翻译成大白话:当一个事物有两个或多个独立变化的维度时,不要用继承,而是用组合的方式将它们连接起来。这个“连接”就是“桥”。


2. 问题场景:为什么需要桥接模式?

想象一个场景:我们要创建不同形状(Shape),并且每个形状可以有不同的颜色(Color)

维度一:形状 (Circle, Square, Triangle...) 维度二:颜色 (Red, Blue, Green...)

如果我们用传统的继承方式来实现,会发生什么?

// 继承会导致“类爆炸”
public abstract class Shape {}
​
public class RedCircle extends Shape {}
public class BlueCircle extends Shape {}
public class GreenCircle extends Shape {}
​
public class RedSquare extends Shape {}
public class BlueSquare extends Shape {}
public class GreenSquare extends Shape {}
​
// ... 如果再加一个Triangle,就要再加3个类
// ... 如果再加一个Yellow,就要再给每个形状都加一个类

问题显而易见:

  • 类爆炸(Class Explosion):类的数量会是“形状数量 × 颜色数量”。每增加一个形状或一个颜色,都需要创建一堆新类。

  • 扩展性极差:如果想增加一个新的形状(比如三角形),就必须为所有已存在的颜色都创建一个对应的三角形子类。反之亦然。

  • 违反单一职责原则:RedCircle 这个类同时承担了定义“形状是圆形”和“颜色是红色”两个职责,耦合度太高。

桥接模式就是为了解决这个问题的。它建议我们把这两个维度分开。


3. 桥接模式的解决方案

桥接模式说:“形状”和“颜色”是两个独立变化的东西,我们应该把它们分开,然后让“形状”持有一个“颜色”的引用。

  1. 抽象部分(Abstraction): 形状(Shape)。它负责高层逻辑,比如“画一个形状”。它内部包含一个指向“实现部分”的引用。

  2. 实现部分(Implementation): 颜色(Color)。它负责底层具体的实现,比如“填充红色”。

这个“持有引用”的动作,就像在“形状”和“颜色”之间架起了一座桥梁。

![alt text](https://refactoring.guru/images/patterns/diagrams/bridge/structure-indexed.png)

我们来对应一下图中的角色:

  • Abstraction (抽象部分): 我们的 Shape 类。它包含一个 Implementor 的引用。

  • RefinedAbstraction (精确抽象部分): 具体的形状,如 Circle, Square。它们继承自 Shape。

  • Implementor (实现部分接口): 我们的 Color 接口。它定义了实现需要遵循的方法,比如 applyColor()。

  • ConcreteImplementor (具体实现部分): 具体的颜色,如 RedColor, BlueColor。它们实现了 Color 接口。


4. 代码实例(Java)

让我们用代码来实现上面的“形状与颜色”的例子。

第1步:创建实现部分(Implementor)的接口和具体实现

这是变化的第一个维度:颜色。

// Implementor: 颜色接口
public interface Color {
    String applyColor();
}
​
// ConcreteImplementor: 红色
public class RedColor implements Color {
    @Override
    public String applyColor() {
        return "涂上了红色";
    }
}
​
// ConcreteImplementor: 蓝色
public class BlueColor implements Color {
    @Override
    public String applyColor() {
        return "涂上了蓝色";
    }
}
第2步:创建抽象部分(Abstraction)和它的引用(桥)

这是变化的第二个维度:形状。注意,Shape 类中包含了一个 Color 引用,这就是桥梁

// Abstraction: 形状抽象类
public abstract class Shape {
    // 关键!这就是桥梁,将Shape和Color连接起来
    protected Color color;
​
    public Shape(Color color) {
        this.color = color;
    }
​
    // 抽象方法,由子类实现
    public abstract String draw();
}
第3步:创建精确抽象部分(Refined Abstraction)

这些是具体的形状,它们继承 Shape 并使用 color 引用来完成自己的功能。

// RefinedAbstraction: 圆形
public class Circle extends Shape {
    public Circle(Color color) {
        super(color); // 调用父类构造函数,把“桥”搭好
    }
​
    @Override
    public String draw() {
        return "绘制一个圆形,并且" + color.applyColor();
    }
}
​
// RefinedAbstraction: 正方形
public class Square extends Shape {
    public Square(Color color) {
        super(color);
    }
​
    @Override
    public String draw() {
        return "绘制一个正方形,并且" + color.applyColor();
    }
}
第4步:客户端调用

现在,我们可以自由地组合形状和颜色了。

public class BridgePatternDemo {
    public static void main(String[] args) {
        // 创建一个红色的圆形
        Shape redCircle = new Circle(new RedColor());
        System.out.println(redCircle.draw()); // 输出: 绘制一个圆形,并且涂上了红色
​
        // 创建一个蓝色的正方形
        Shape blueSquare = new Square(new BlueColor());
        System.out.println(blueSquare.draw()); // 输出: 绘制一个正方形,并且涂上了蓝色
​
        // 现在,想创建一个蓝色的圆形,非常容易!
        Shape blueCircle = new Circle(new BlueColor());
        System.out.println(blueCircle.draw()); // 输出: 绘制一个圆形,并且涂上了蓝色
​
        // 如果要增加一个新的形状“三角形”,只需要:
        // 1. 创建一个 Triangle 类继承 Shape
        // 完全不需要动任何颜色的代码!
​
        // 如果要增加一个新的颜色“绿色”,只需要:
        // 1. 创建一个 GreenColor 类实现 Color 接口
        // 完全不需要动任何形状的代码!
    }
}

5. 优点与缺点

优点:

  1. 分离抽象和实现:这是最核心的优点,让两边可以独立地扩展,互不影响。

  2. 极大地提高了扩展性:如上例所示,增加新形状或新颜色都变得非常简单。

  3. 符合单一职责原则:每个类的职责更清晰。Shape 管形状,Color 管颜色。

  4. 对客户端隐藏实现细节:客户端(main方法)只需要和 Shape 这个高层抽象打交道,不需要知道具体的 Color 是如何实现的。

缺点:

  1. 增加了系统的复杂性:引入了更多的类和接口,如果系统本身很简单,使用桥接模式可能会让设计变得过度复杂。

  2. 理解难度:对于新手来说,需要理解“抽象”和“实现”的分离,比简单的继承要多绕一个弯。

6. 与适配器模式(Adapter)的区别

这是一个非常常见的混淆点。

  • 目的不同

    • 桥接(Bridge):是设计时的决策。目的是分离抽象和实现,让它们可以独立变化。它是一种主动的、有预谋的架构设计。

    • 适配器(Adapter):是补救时的措施。目的是让两个已经存在但互不兼容的接口能够协同工作。它是一种被动的、为了解决兼容性问题的补丁。

  • 结构不同

    • 桥接模式是两个独立变化的维度通过组合连接。

    • 适配器模式是通过封装一个对象,提供一个不同的接口来包装它。

一个比喻

  • 桥接:你正在设计一个全新的笔记本电脑,你决定使用通用的 Type-C 接口(实现部分),这样你的电脑(抽象部分)未来就可以连接任何符合 Type-C 标准的设备(显示器、充电器、硬盘等)。

  • 适配器:你有一台只有 USB-A 接口的老电脑,现在买了一个只有 Type-C 接口的新硬盘。为了让它们能工作,你去买了一个“USB-A 转 Type-C”的适配器。


总结

当你发现一个类存在两个或多个独立变化的维度,并且你不想使用继承导致类爆炸时,就应该立刻想到桥接模式。它通过组合/聚合关系代替继承,在两个维度之间架起一座灵活的桥梁,从而构建出松耦合、高扩展性的系统。


网站公告

今日签到

点亮在社区的每一天
去签到