学习设计模式——桥接模式

2,473 阅读4分钟

定义

桥接模式(Bridge Pattern),也叫做桥梁模式,结构型设计模式的一种,这个模式相对来说有些难理解。桥接,顾名思义,就是用来连接两个部分,为被分离了的抽象部分和实现部分搭桥。

官方一点的说法叫:将抽象部分与它的实现部分分离,使它们都可以独立变化。

还有另外一种理解方式:一个类存在两个(或多个)独立变化的维度,我们通过组合的方式,让这两个(或多个)维度可以独立进行扩展。

适用场景:

  • 如果一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,可以通过桥接模式使他们在抽象层建立一个关联关系;

  • 那些不希望使用继承或因为多层次继承导致系统类的个数极具增加的系统;

  • 一个类存在两个独立变化的维度,而这两个维度都需要进行扩展。

UML 类图

image.png

观察上面的 UML 类图,我们可以发现,桥接模式分为以下四个角色:

  1. Abstract: 定义抽象接口,拥有一个Implementor类型的对象引用
  2. RefinedAbstraction: 扩展Abstraction中的接口定义
  3. Implementor: 实现部分,可以为接口或者是抽象类,其方法不一定要与抽象部分中的一致,一般情况下是由实现部分提供基本的操作,而抽象部分定义的则是基于实现部分基本操作的业务方法
  4. ConcreteImplementorA 和 ConcreteImplementorB: 实现Implementor接口,给出具体实现

基于上面的各个角色,我们就可以写出桥接模式的通用代码。

通用代码

首先是实现部分代码:

Implementor.java

public interface Implementor {
    void operationImpl();
}

ConcreteImplementorA.java

public class ConcreteImplementorA implements Implementor{
    @Override
    public void operationImpl() {
        // 具体实现
    }
}

ConcreteImplementorB.java

public class ConcreteImplementorB implements Implementor {
    @Override
    public void operationImpl() {
        // 具体实现
    }
}

然后是抽象部分的代码: Abstraction.java

public abstract class Abstraction {
    private Implementor implementor;

    public Abstraction(Implementor implementor) {
        this.implementor = implementor;
    }

    public void operation() {
        implementor.operationImpl();
    }
}

RefinedAbstraction.java

public class RefinedAbstraction extends Abstraction{

    public RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }

    @Override
    public void operation() {
        // 对 Abstraction 中的 operation() 方法进行扩展
    }
}

使用

public class Test {
    public static void main(String[] args) {
        Implementor concreteImplementorA = new ConcreteImplementorA();
        Abstraction refinedAbstraction = new RefinedAbstraction(concreteImplementorA);
        refinedAbstraction.operation();
    }
}

看了上面的通用代码实现之后,相信你对桥接模式的实现结构已经比较清楚了。

当然上面的通用代码只是最常用的实现方式而已,在实际情况中可能会有其他情况,比如 RefinedAbstraction 类根据实际情况是可以有多个的。 ConcreteImplementor实现类也可能有一个或多个。

有了上面的通用代码,我们就可以根据实际情况来套用上面通用代码结构了。接下来我们看一个实例。

实例

假设我们有一个画笔,可以画正方形、长方形、圆形。现在我们需要给这些形状进行上色,这里有三种颜色:白色、灰色、黑色。这里我们可以画出3*3=9种图形:白色正方形、白色长方形、白色圆形。。。。。。

此时我们可以将图形和颜色抽象出来,根据实际需要对颜色和形状进行组合。

image.png 对于这样的实现方案,我们就可以称之为桥接模式

UML 类图

类比通用的类图,我们可以得到如下具体的类图:

image.png

代码实现

形状类 Shape.java

public abstract class Shape {
    Color color;

    public void setColor(Color color) {
        this.color = color;
    }

    public abstract void draw();
}

三种形状 Circle.java、Rectangle.java、Square.java

public class Circle extends Shape {
    @Override
    public void draw() {
        color.bepaint("正方形");
    }
}

public class Rectangle extends Shape {
    @Override
    public void draw() {
        color.bepaint("长方形");
    }
}

public class Square extends Shape {
    @Override
    public void draw() {
        color.bepaint("正方形");
    }
}

颜色接口 Color.java

public interface Color {
    void bepaint(String shape);
}

三种颜色 White.java、Gray.java、Black.java

public class White implements Color {
    @Override
    public void bepaint(String shape) {
        System.out.println("白色的" + shape);
    }
}

public class Gray implements Color {
    @Override
    public void bepaint(String shape) {
        System.out.println("灰色的" + shape);
    }
}

public class Black implements Color {
    @Override
    public void bepaint(String shape) {
        System.out.println("黑色的" + shape);
    }
}

测试 Test.java

public class Test {
    public static void main(String[] args) {
        // 白色
        Color white = new White();
        // 正方形
        Shape square = new Square();
        // 白色的正方形
        square.setColor(white);
        square.draw();

        // 长方形
        Shape rectange = new Rectangle();
        rectange.setColor(white);
        rectange.draw();
    }
}

运行结果:

白色的正方形
白色的长方形

以上案例来自www.cnblogs.com/chenssy/p/3…

总结

对于桥接模式的定义:将抽象和实现解耦,让它们可以独立变化。 这里的“抽象”,指的并非“抽象类”或“接口”,而是被抽象出来的一套“类库”,它只包含骨架代码,真正的业务逻辑需要委派给定义中的“实现”来完成。而定义中的“实现”,也并非“接口的实现类”,而是的一套独立的“类库”。“抽象”和“实现”独立开发,通过对象之间的组合关系,组装在一起。

JDBC 驱动是桥接模式的经典应用。如果我们想要把 MySQL 数据库切换成 Oracle 数据库,只需要更换数据库驱动,动一行代码就可以实现了:

将com.mysql.jdbc.Driver 换成 oracle.jdbc.driver.OracleDriver。