结构型-桥接模式


一、意图

桥接模式是一种结构型设计模式, 可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构, 从而能在开发时分别使用。

二、问题

假如你有一个几何形状Shape类, 从它能扩展出两个子类: 圆形 Circle 和 方形Square。 你希望对这样的类层次结构进行扩展以使其包含颜色, 所以你打算创建名为 红色Red蓝色Blue的形状子类。 但是, 由于你已有两个子类, 所以总共需要创建四个类才能覆盖所有组合, 例如 蓝色圆形Blue Circle红色方形Red Square

image-20221215213149498

在层次结构中新增形状和颜色将导致代码复杂程度指数增长。 例如添加三角形状, 你需要新增两个子类, 也就是每种颜色一个; 此后新增一种新颜色需要新增三个子类, 即每种形状一个。

三、解决方案

问题的根本原因是我们试图在两个独立的维度——形状与颜色——上扩展形状类。 这在处理类继承时是很常见的问题。

桥接模式通过将继承改为组合的方式来解决这个问题。 具体来说, 就是抽取其中一个维度并使之成为独立的类层次, 这样就可以在初始类中引用这个新层次的对象, 从而使得一个类不必拥有所有的状态和行为。

image-20221215213407477

根据该方法, 我们可以将颜色相关的代码抽取到拥有 红色蓝色两个子类的颜色类中, 然后在 形状类中添加一个指向某一颜色对象的引用成员变量。 现在, 形状类可以将所有与颜色相关的工作委派给连入的颜色对象。 这样的引用就成为了 形状颜色之间的桥梁。 此后, 新增颜色将不再需要修改形状的类层次, 反之亦然。

四、代码

理解桥梁模式,其实就是理解代码抽象和解耦。

1、颜色顶层接口

我们首先需要一个桥梁,它是一个接口,定义提供的接口方法。

public interface DrawAPI {   
    public void draw();
}

2、具体颜色的实现类

public class RedPen implements DrawAPI {
    @Override
    public void draw() {
        System.out.println("红色");
    }
}
public class GreenPen implements DrawAPI {
    @Override
    public void draw() {
        System.out.println("绿色");
    }
}
public class BluePen implements DrawAPI {
    @Override
    public void draw() {
        System.out.println("蓝色");
    }
}

3、形状抽象类

定义一个抽象类,此类的实现类都需要使用 DrawAPI:

public abstract class Shape {

    protected DrawAPI drawAPI;

    protected Shape(DrawAPI drawAPI) {
        this.drawAPI = drawAPI;
    }

    public abstract void draw();
}

4、完整功能的子类

// 圆形
public class Circle extends Shape {

    private int radius;

    public Circle(int radius, DrawAPI drawAPI) {
        super(drawAPI);
        this.radius = radius;
    }

    public void draw() {
        drawAPI.draw();
    }
}
// 长方形
public class Rectangle extends Shape {

    private int x;
    private int y;

    public Rectangle(int x, int y, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;
        this.y = y;
    }
    public void draw() {
        drawAPI.draw(0, x, y);
    }
}

5、测试

public static void main(String[] args) {

    Shape greenCircle = new Circle(10, new GreenPen());

    Shape redRectangle = new Rectangle(4, 8, new RedPen());

    greenCircle.draw();

    redRectangle.draw();
}

五、使用场景

如果你想要拆分或重组一个具有多重功能的庞杂类 (例如能与多个数据库服务器进行交互的类), 可以使用桥接模式。

类的代码行数越多, 弄清其运作方式就越困难, 对其进行修改所花费的时间就越长。 一个功能上的变化可能需要在整个类范围内进行修改, 而且常常会产生错误, 甚至还会有一些严重的副作用。

桥接模式可以将庞杂类拆分为几个类层次结构。 此后, 你可以修改任意一个类层次结构而不会影响到其他类层次结构。 这种方法可以简化代码的维护工作, 并将修改已有代码的风险降到最低。

如果你希望在几个独立维度上扩展一个类, 可使用该模式。

桥接建议将每个维度抽取为独立的类层次。 初始类将相关工作委派给属于对应类层次的对象, 无需自己完成所有工作。

如果你需要在运行时切换不同实现方法, 可使用桥接模式。

当然并不是说一定要实现这一点, 桥接模式可替换抽象部分中的实现对象, 具体操作就和给成员变量赋新值一样简单。

顺便提一句, 最后一点是很多人混淆桥接模式和策略模式的主要原因。 记住, 设计模式并不仅是一种对类进行组织的方式, 它还能用于沟通意图和解决问题。


  目录