【设计模式】桥接模式

1,355 阅读5分钟

本文主要介绍:桥接模式概念和用法。

模式背景

生活中,我们如果一个笔有三种型号:大,中,小。颜色一共有M种。如果需要所有型号都有相对应的颜色,那么就需要3*M只笔。但是如果我们转换一下:M种颜色代表M种墨水,笔的三种型号就对应三支笔,那么只需要3+M个,然后组合就可以得到相同的结果,这种思维模式就是桥接。

应用到项目中,当系统中一些类存在多个独立变化的维度(注意2点:独立变化维度),我们可以使用桥接模式来大大减少系统的中的类。如果不使用桥接模式,一般来说我们会形成一个庞大的继承系统(见下面的图2),这些变化的维度将耦合在一起,对于扩展什么的也会极为不便(无论是我们现在需要增加一个颜色,还是增加一个笔型号,势必都要添加大量的类)。

定义&概念

桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

原理

如上面提到的,桥接模式需要先能分出系统中那些独立变化的维度,然后我们再进行分离。桥接模式的思想就是如何进行分离的过程

所有设计模式的思想其实都希望我们更多的去利用组合,而不是继承。所以桥接模式的主要思想就是:将变化的维度抽象为不同的继承体系,每一个维度是自己的一个继承体系,然后通过组合将所需要的这些变化维度拼接为最后的对象。这维度和维度之间的联系组合我们把它称为桥。如下图Color和Pen之间就是一座桥,这个桥所连接是两个继承体系。两个继承体系独立变化。桥接模式主要是用来处理多维度变化的。

组成要素

  • 抽象类(Abstraction)
    • 将原来的那个设计多维度的变化的对象。这个抽象类主要担当接口的作用!用来多态其实现类的。
  • 抽象类的扩充(RefinedAbstraction)
    • 也可以理解为抽象类的具体实现类。他相当于就完成各种变化的最终组合的实现类,组合方式就是调用桥的另一个组合对象来动态完成组合的。我们可以将其中一种变化放入到该抽象类实现中去。比如上面Pen的大小。这样Pen内部通过多态的Color来组合不同的情况。
  • 实现类接口(Implementor)
    • 定义实现类的接口,是桥的另一端的继承体系的祖宗。只封装一个变化。
  • 实现类的具体实现类(ConcreteImplementor)
    • 就是该维度变化的各种情况的实现。

UML

生活模型

  • 如果不使用桥接模式,就可能形成这样的继承体系。

  • 使用了桥接模式

系统模型

实现

/**
 * 抽象类
 */
abstract class Pen {
    Color color;

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

    abstract void size();
}

/**
 * 某个变化维度的接口
 */
interface Color {
    void color();
}

/**
 * 变化维度接口的实现
 */
class Red implements Color {
    @Override
    public void color() {
        System.out.println("red");
    }
}

class Black implements Color {
    @Override
    public void color() {
        System.out.println("black");
    }
}

class Blue implements Color {
    @Override
    public void color() {
        System.out.println("blue");
    }
}

/**
 * 抽象类的具体实现
 */
class Pen1 extends Pen {
    @Override
    void size() {
        color.color();
        System.out.println("size:1");
    }
}

class Pen2 extends Pen {
    @Override
    void size() {
        color.color();
        System.out.println("size:2");
    }
}

使用

Pen p = new Pen1();
Color c = new Red();
p.setColor(c);
p.size();

优缺点

整体来看,桥接模式的优缺点如下:

优点

  • 解耦了继承体系。
  • 分离抽象接口及其实现部分。提高了比继承更好的解决方案。
  • 提高系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原代码。

缺点

  • 增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
  • 要求正确识别出系统中变化的维度,这让其使用范围具有一定的局限性。

使用场景

  1. 存在着独立的变化维度,且这些维度都需要进行扩展。
  2. 当我们系统中使用继承的时候,如果发现继承体系是可以继续拆分的,那么就使用桥接进行拆分。
  3. 是实现java虚拟机和jdbc这些程序的核心设计模式之一。
  4. 最好的就是和笔+油墨这类性质问题,那么就使用桥接模式。

总结

  1. 系统存在多个相互独立的变化维度,使用桥接第一步就是先分清这些维度。
  2. 每个维度一个继承体系,比如笔是一个继承体系,颜色是一个继承体系。最后使用组合拼成最终对象。
  3. 当系统中有一个继承体系庞大,你可以考虑看看这个继承是否可以按照维度进行拆分,然后使用桥接来组合。
  4. 桥接模式不是一个复杂的模式,他的工作就2个:按维度建立继承体系,将不同体系连一起(称为桥接)。

扩展

和适配器模式连用

桥接模式是设计初期的,适配器模式是可能开发中期的。他们位于系统设计的不同阶段。当我们发现现有的类和我们正在开发的系统无法协同工作就可以使用适配器模式。而所适配的可能就是桥接的某个维度接口的某个功能实现。比如:一个系统的数据采集可以有文本,csv,数据库,我们有现成的数据库的连接库,这时候就要一个适配器来适配这个库,并实现数据采集的接口来实现桥接。

相关代码:github.com/zhaohaoren/…

如有代码和文章问题,还请指正!感谢!