设计之禅——桥接模式

2020-09-07 10:47:48 浏览数 (1)

前言

桥接模式也是经典的23种模式之一,不过在《HeadFirst设计模式》书中只对其做了一个简短的描述,本文则是根据网络上的博客得出的个人理解和总结。

正文

定义

在维基百科上是这样定义桥接模式的:

桥接模式是软件设计模式中最复杂的模式之一,它把事物对象和其具体行为、具体特征分离开来,使它们可以各自独立的变化。

桥接模式被列为最复杂的模式之一,它的复杂不在于代码的实现上,而是在于在软件设计之初就要对抽象对象和具体实现的进行准确的把控。那什么是抽象对象?什么又是具体实现?如何区分?

实例

在网上看到一个非常生动的例子。蜡笔和毛笔。对于这两种笔,都有两个会使其发生改变的原因:型号和颜色。假设需要提供三种(大、中、小)型号和七种颜色,那么蜡笔就需要21支,毛笔则只需要3只,颜料7种,加起来才10种,远小于21种。未来如果增加一种型号和一种颜色,蜡笔就要增加11支,毛笔则只需要增加一支该型号的笔和一种新的颜料。这里毛笔就是桥接模式的体现,因此,桥接模式的一大优点就是大幅度减少类的数目。通过两者的uml图来说明:

上面是蜡笔的实现,毛笔则大不相同:

从面向对象设计角度考虑,对于笔而言有了两个使它改变的原因, 蜡笔将这两个改变因素融合在了一起,使用了多层继承形成强耦合,违反了单一职责原则,而毛笔则通过组合,将两个维度的变化分离出来,在自己的方向上的改变是独立的,而两者直接是通过组合关联在一起的(就像桥一样,桥接因此得名),降低了耦合性,这样既不会影响到原先的设计,也不会呈现出类爆炸的现象。

那按照上面的定义,抽象对象是Brush还是Color呢?这个和我平时所学的抽象和实现不太一样啊,貌似它们都是抽象的接口啊?

确实,这里的抽象对象和实现不是片面的接口和实现类的关系,而是指在两个变化维度上,一个更像是抽象出来的固有对象,而另一个则是附加于该对象上的特性、行为等。比较毛笔的类图,我们来看看桥接模式的真正类图:

不难理解,在毛笔的例子中,型号应是毛笔固有的属性,因此,将型号和毛笔作为抽象的对象,而颜色则是通过人为设置和附加其上的,作为具体的实现。

这貌似并不复杂。

是的,这个例子看起来非常容易理解,但在实际的开发中,要在设计初期精准预测把控哪些是可变化的维度实际上并非这么容易的,需要经验的积累,同时某些时候导致变化的维度不止两个,这种情况下还能使用桥接模式么?(当然可以)为什么?

Coding

说了这么多,是时候show ur code了,首先创建出我们的抽象对象族:

代码语言:javascript复制
// 抽象的毛笔
public abstract class WrittingBrush {

    protected String size;
    protected Color color;

    /**
     * 通过该方法为毛笔着色
     */
    public void setColor(Color color) {
        this.color = color;
        System.out.println(size   "毛笔开始着色:"   color.getHue());

    }
}

// 各种型号的毛笔,这是大毛笔
public class BigWrittingBrush extends WrittingBrush {

    public BigWrittingBrush() {
        this.size = "大";
    }

}

然后是颜色族

代码语言:javascript复制
public abstract class Color {

    protected String hue;

    public String getHue() {
        return hue;
    }

}

public class Red extends Color {
    public Red() {
        this.hue = "红色";
    }
}

你可以随意组合它们,就像下面这样:

代码语言:javascript复制
    public static void main(String[] args) {
        Color red = new Red();
        Color green = new Green();
        Color black = new Black();

        WrittingBrush brush = new BigWrittingBrush();
        brush.setColor(red);
        brush.setColor(green);
        brush.setColor(black);

        brush = new MediumWrittingBrush();
        brush.setColor(red);
        brush.setColor(green);
        brush.setColor(black);
    }

打印如下结果:

代码语言:javascript复制
大毛笔开始着色:红色
大毛笔开始着色:绿色
大毛笔开始着色:黑色
中毛笔开始着色:红色
中毛笔开始着色:绿色
中毛笔开始着色:黑色

总结

桥接模式是一个非常实用的模式,在遇到有多个变化维度就可以考虑桥接模式,它具有如下优点:

  • 遵循单一职责原则,将一个或多个维度的变化解耦。
  • 抽象和实现可以独立的扩展,却不会影响到双方以及原设计。
  • 使用桥接模式比多层继承能够大大降低类的数量。
  • 良好的遵循了单一职责原则、合成复用原则、里式代换原则、开闭原则、依赖倒置原则

但在使用桥接模式需要正确识别出系统中两个或多个独立变化的维度,增加了设计的难度和复杂度。


参考
  • 处理多维度变化——桥接模式
  • Java设计模式
  • Bridge Design Pattern
  • 维基百科

0 人点赞