Bridge作为桥梁,作用是将类的功能层次结构和类的实现层次结构里连接起来。
类的层次结构的两个作用:
希望增加新功能时:
想在类中增加新功能时,会编写一个该类的子类,这样就构成了一个小小的类层次结构。这样就构成了一个小小的类层次结构。
- 父类具体基本功能
- 在子类中增加新的功能
随着功能的越来越多,类的结构越来越深,但是通常来说,类的层次结构不宜与过深。这种层次被称为类的功能层次结构。
希望增加新的实现时:
在Template Method模式中,可以看出抽象类声明了一些抽象方法,定义了一些接口,然后通过子类负责去实现这些抽象功能。父类的任务是通过声明抽象方法的方式定义接口,而子类的任务则是实现抽象方法。这类方法中的层次结构并非是为了增加新的功能,而是为了增加实现。这种结构被称为类的实现层次结构。
类的层次结构的混杂与分离:
在编写子类的时候,首先需要明确自己的目的和意图:“到底是需要增加功能还是增加实现”。当类的层次结构只有一层时,功能层次结构与实现层次结构是混杂在一个层次结构中的,只有很容易使类的层次结构变得复杂,也难以理解,因此无法确定究竟在类的哪一个层次结构中去增加子类。
所以,需要将“类的功能层次结构”和“类的实现层次结构”分离为两个独立的类层次结构。如果仅仅是简单的将它们分开,两者之间必然会缺乏联系,所以需要用Bridge模式搭建桥梁。
代码实例:
类的功能层次结构:Display类:
Display类的功能是抽象的,其impl字段保存了实现了Display类的具体功能的实例。该实例通过Display的构造函数被传递到Display类,然后保存在impl字段中,以供后续的处理使用。
open、print、close这三个方法分别是Display类提供的接口,其都调用了impl字段中的实现方法,将Display接口转换成为了DisplayImpl的接口。
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();}}
类的功能层次结构:CountDisplay:
CountDisplay类再Display类的基础上增加了一个新功能。继承了Display类的三个基础方法,并使用其来增加这个新功能。
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();}}
类的实现层次与结构:DisplayImpl类:
这个类属于抽象类,声明了3个抽象方法。
public abstract class DisplayImpl {public abstract void rawOpen();public abstract void rawPrint();public abstract void rawClose();}
类的实现层次结构:StringDisplayImpl类:
继承了DisplayImpl类,对其中的抽象方法进行实现。
public class StringDisplayImpl extends DisplayImpl{private String string;private int width;public StringDisplayImpl(String string) {this.string = string;this.width = string.length();}@Overridepublic void rawOpen() {printLine();}@Overridepublic void rawPrint() {System.out.println("|"+string+"|");}@Overridepublic void rawClose() {printLine();}private void printLine() {System.out.print("+");for (int i = 0; i < width; i++) {System.out.print("-");}System.out.println("+");}}
Main类:
将上述4个类进行组合,因此可以调用它们的display方法。
Bridge模式中的登场角色:
Abstraction(抽象化):
该角色位于“类的功能层次设计”最上层,使用Implementor角色的方法定义了基本的功能。该角色中保存了Implementor角色的实例。
RefinedAbstraction(改善后的抽象化):
Implementor(实现者):
该角色位于“类的实现层次结构”最上层。定义了用于实现Abstraction角色功能的接口。
ConcreteImplementor(具体实现者):
该角色负责实现Implementor中定义的接口。
拓展思路的要点:
扩展性:
Bridge模式的特征是将“类的功能层次设计”和“类的实现层次结构”分离开了,将类的这两个层次结构分开更有利于独立地对它们进行扩展。
当想要增加功能的时候仅仅需要在“类的功能层次设计”一侧增加类即可,不必对“类的实现层次结构”做任何修改。而且,增加后的功能可以被“所有的实现”使用。
继承和委托:
继承是强关联,委托是弱关联。虽然使用“继承”很容易扩展类,但是类之间也形成了一种强关联关系。
如果想要很轻松地改变类之间的关系,使用继承就不太合适了,因为每次改变类之间的关系时都需要修改代码,所以可以使用“委托”来代替“继承”关系。
在上述代码中,当其他类要求Display类“工作”的时候,Display类并非是自己工作,而是将工作交给“impl”,实现委托。
只有Display的实例生成的时候,才与作为参数被传入的类构成关联。如果不传递某一实现的实例,而是更换传入的类,就可以很容易地改变实现。这个时候,发生变化的代码只有Main类,Display和DisplayImpl都不需要做任何修改。
相关的设计模式:
Template Method模式:
在Template Method中使用了“类的实现层次结构”,父类调用抽象方法,而子类实现抽象方法。
Abstract Factory模式:
能够根据需求设计出良好的具体实现者角色,有时会使用这个模式。
Adapter模式:
使用Bridge模式可以达到类的功能层次结构与类的实现层次结构分离的目的,并在此基础上使这些层次结构结合起来。
而使用Adapter模式则可以结合哪些功能上相似但是接口不同的类。
