一天一个设计模式——Bridge桥接模式

一、概念准备

  在理解桥接模式之前,先要理解面向对象程序设计中的两个概念:

  • 类的功能层次结构:假设现在有一个类Something,这个类有一些成员属性和成员方法,但是现有的功能不能满足要求,因此我们想扩展这个类,给这个类创建一个子类SomethingBetter来继承它,并在子类中添加更多属性和方法。像这样不同的功能位于不同的类继承结构中,就构成了类的功能层次结构。
  • 类的实现层次结构:回顾一下抽象类的作用,抽象类声明抽象方法(定义了方法接口API),然后在继承它的子类中实现相关方法。由于我们将方法定义和实现分离到了不同的类中,从而实现了类的高可替换性,并有了模板Template Method方法模式。虽然这里也有父类和子类的继承关系,但是这里的继承并不是为了增加新功能,而是为了完成“定义——实现 分离”中的实现环节。这种层次结构就是类的实现层次接口。

二、模式说明

  如果类的设计都只有一层(程序中自定义的类不存在继承关系),这时候类的功能层次结构和实现层次结构是混杂在一起的,也很难扩展(无法确定应该继承哪个类来扩展功能,同一个方法如果想替换其实现也无法做到)。因此需要按照上面说的,将类的功能层次和实现层次分开,为了在分开后能继续保持一定的联系,这时候就需要一个桥梁,将它们连接起来。(Bridge也有桥梁的意思,连接两个事物)

三、代码示例

  在下面的桥接模式代码示例中,着重关注哪些时功能层次,哪些是实现层次,二者又是如何桥接起来的。

1、类的功能层次结构

Display类:Display类的功能是抽象的,负责“显示”一些东西,它位于功能层次结构的最上层。open、print、close这三个方法是Display类提供的接口,它们定义了显示的步骤,这三个方法调用的是Display实现类的对象。

一天一个设计模式——Bridge桥接模式
package com.designpattern.cn.bridgepattern;

public class Display {
    private DisplayImpl impl;
    public Display(DisplayImpl impl){
        this.impl = impl;
    }
    public void open(){
        impl.rawOpen();
    }
    public void print(){
        impl.rawPrint();
    }
    public void close(){
        impl.rawClose();
    }
    public final void display(){
        open();
        print();
        close();
    }
}
View Code

CountDisplay类:CountDisplay类在Display类的基础上增加了一个新功能,具有“只显示规定次数”的功能。因此,这属于“类的功能层次范畴”。

一天一个设计模式——Bridge桥接模式
package com.designpattern.cn.bridgepattern;

public class CountDisplay extends Display {
    public CountDisplay(DisplayImpl impl){
        super(impl);
    }
    public void multiDisplay(int times){
        open();
        for(int i=0; i < times; i++){
            print();
        }
        close();
    }
}
View Code

 

2、类的实现层次结构

DisplayImpl类:位于“类的实现层次结构”的最上层。DisplayImpl是抽象类,声明了rawOpen、rawPrint、rawClose三个抽象方法。

一天一个设计模式——Bridge桥接模式
package com.designpattern.cn.bridgepattern;

public abstract class DisplayImpl {
    public abstract void rawOpen();
    public abstract void rawPrint();
    public abstract void rawClose();
}
View Code

 

StringDisplayImpl类:它是仙子字符串的类,但它并不是直接显示字符串,而是继承了DisplayImpl类,作为子类来使用rawOpen、rawPrint、rawClose三个方法显示字符串。

一天一个设计模式——Bridge桥接模式
package com.designpattern.cn.bridgepattern;

public class StringDisplayImpl extends DisplayImpl {
    private String string;
    private int width;
    public StringDisplayImpl(String string){
        this.string = string;
        this.width = string.getBytes().length;
    }
    @Override
    public void rawOpen(){
        printLine();
    }
    @Override
    public void rawPrint(){
        System.out.println("|" + string + "|");
    }
    @Override
    public void rawClose() {
        printLine();
    }

    private void printLine(){
        System.out.print("+");
        for(int i = 0; i < width; i++){
            System.out.println("-");
        }
        System.out.println("+");
    }
}
View Code

 

3、Main类测试结果

一天一个设计模式——Bridge桥接模式

 

四、模式类图

一天一个设计模式——Bridge桥接模式

五、模式中的角色

  • Abstraction抽象化:类的功能层次的最上层,它使用Implementor角色的方法定义了基本功能,如上面的Display类。
  • RefinedAbstraction改善后的抽象化:增加了Abstraction的功能,如上面的CountDisplay类。
  • Implementor实现者:类的实现层次结构最上层,定义了用于实现Abstraction的角色的接口方法,如上面的DisplayImpl类。
  • ConcreteImplementor具体实现者:负责实现Implementor角色定义的接口方法,如上面的StringDisplayImpl类。

那么,这其中的桥梁Bridge是什么呢?对于示例程序,Display类和DisplayImpl是如何关联的,从程序中看出,这里的桥梁应该是impl字段。

六、相关的设计模式

  • 模板方法Template Method模式:模板方法模式就是使用了桥接模式中的类的实现层次结构。父类调用抽象方法,子类实现具体方法。
  • 抽象工厂Abstract Factory模式:可以使用抽象工厂设计出更好的ConcreteImplementor类。
  • 适配器Adapter模式:桥接模式连接了类的结构层次和实现层次,适配器模式则将功能类似,但是接口不匹配的类结合在一起。

七、扩展

  • 采用bridge桥接模式分离功能层次和实现层次,更有利于类的扩展,如果要增加功能,只需在功能层次这一侧做修改,无需调整实现层次,并且所有的实现层次都能利用增加的功能。
  • 继承是强关联,委托是弱关联。继承可以方便的得到功能更强的类,但是一旦使用继承,则在类之间形成了强关联关系,如果想改变或者替换其中的一个类,就必须修改类的代码。上面的例子中,使用了委托,只有当Display类的实例生成时,才作为参数,与被传入的类构成关联关系(示例程序中,只有Main类生成Display类和CountDisplay类的实例时,才将StringDisplayImpl类的实例作为参数传递给Display类和CountDisplay类)。除了StringDisplayImpl类,我们可以使用任意一个ConcreteImplementor角色传递给Display类和CountDisplay类,就能很容易的改变实现(只需修改Main类,Display类和DisplayImpl无需任何修改)。
上一篇:Openvswitch手册(1): 架构,SSL, Manager, Bridge


下一篇:Docker的网络模式