Java 设计模式07——桥接模式

引子

假设有一个绘制图形并上色的需求,要绘制的图形有三种:圆形、正方形、三角形,可以上的颜色有三种:红色、绿色和蓝色。也就是说最终可能有九种组合,这时有多种实现方式:

  1. 定义相应的图形,通过继承,分别实现红色圆形、绿色圆形、蓝色圆形等,这样子类就有9个;
  2. 按图形和颜色两个维度,定义好图形和颜色,然后按需要将他们进行组合;

上面的方式一实现很简单,也容易理解,但会导致类的数据过多,而且如果我需要新增一种图形或颜色,就需要重新写子类,导致类的结构过于臃肿,而方式二利用的就是桥接模式的思想,能很好的解决这种场景下的问题。

模式定义

桥接模式,结构性模式,即将抽象部分与实现部分分离,使他们可以独立变化。那上面的场景来说,我们要实现的部分是绘制带有颜色的形状,那么要实现的部分就可以抽象出形状颜色两个类,然后将形状和颜色关联起来,这样就可以将形状和颜色自由组合了。

将抽象部分与他的实现部分分离套用《大话设计模式》里面的就是实现系统可能有多个角度分类,每一种角度都可能变化,那么把这种多角度分类给分离出来让他们独立变化,减少他们之间耦合。

桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化,这就是桥接模式的用意。

代码示例

  1. 定义形状父类Shape,Shape和Color关联起来了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public abstract class Shape {
    Color color;

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

    public abstract void draw();
    }
  2. 定义三种形状:圆、正方形、三角形

    1
    2
    3
    4
    5
    6
    public class Circle extends Shape{
    @Override
    public void draw() {
    color.paint("圆");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Square extends Shape{
    @Override
    public void draw() {
    color.paint("正方形");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Triangle extends Shape {
    @Override
    public void draw() {
    color.paint("三角形");
    }
    }
  3. 定义颜色接口Color

    1
    2
    3
    4
    5
    public interface Color {
    String colorName();

    void paint(String shapeName);
    }
  1. 定义三种颜色

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class RedColor implements Color {

    @Override
    public String colorName() {
    return "红色的";
    }

    @Override
    public void paint(String shapeName) {
    System.out.println(colorName() + shapeName);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class GreenColor implements Color {
    @Override
    public String colorName() {
    return "绿色的";
    }

    @Override
    public void paint(String shapeName) {
    System.out.println(colorName() + shapeName);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class BlueColor implements Color {
    @Override
    public String colorName() {
    return "蓝色的";
    }

    @Override
    public void paint(String shapeName) {
    System.out.println(colorName() + shapeName);
    }
    }
  2. 定义Client来进行验证

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class Client {
    public static void main(String[] args) {
    // 蓝色的圆
    Shape circle = new Circle();
    circle.setColor(new BlueColor());
    circle.draw();

    // 红色的正方形
    Shape square = new Square();
    square.setColor(new RedColor());
    square.draw();

    // 绿色的三角形
    Shape triangle = new Triangle();
    triangle.setColor(new GreenColor());
    triangle.draw();
    }
    }
    // 输出结果
    蓝色的圆
    红色的正方形
    绿色的三角形

模式总结

优缺点

从上面的例子可以总结出桥接模式一下的优缺点:

  • 优点
    1. 分离了抽象部分(Shape和Color)与实现部分(具体的形状和具体的颜色)提供了比继承更好的解决方案;
    2. 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统;
    3. 客户无需关心实现部分的细节。
  • 缺点
    1. 增加了系统设计的难度,因为聚合关系是建立在抽象层的(那上面例子来说就是Shape和Color关联起来了)
    2. 使用场景比较单一,适用于能提取出独立变化的维度的系统。

适用场景

  • 1、如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
  • 2、对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
  • 3、一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

总结

  • 1、桥接模式实现了抽象化与实现化的脱耦。他们两个互相独立,不会影响到对方。
  • 2、对于两个独立变化的维度,使用桥接模式再适合不过了。
  • 3、对于”具体的抽象类”所做的改变,是不会影响到客户。