Bridge作为桥梁,作用是将类的功能层次结构和类的实现层次结构里连接起来。

类的层次结构的两个作用:

希望增加新功能时:

想在类中增加新功能时,会编写一个该类的子类,这样就构成了一个小小的类层次结构。这样就构成了一个小小的类层次结构。

  • 父类具体基本功能
  • 在子类中增加新的功能

随着功能的越来越多,类的结构越来越深,但是通常来说,类的层次结构不宜与过深。这种层次被称为类的功能层次结构

希望增加新的实现时:

在Template Method模式中,可以看出抽象类声明了一些抽象方法,定义了一些接口,然后通过子类负责去实现这些抽象功能。父类的任务是通过声明抽象方法的方式定义接口,而子类的任务则是实现抽象方法。这类方法中的层次结构并非是为了增加新的功能,而是为了增加实现。这种结构被称为类的实现层次结构

类的层次结构的混杂与分离:

在编写子类的时候,首先需要明确自己的目的和意图:“到底是需要增加功能还是增加实现”。当类的层次结构只有一层时,功能层次结构与实现层次结构是混杂在一个层次结构中的,只有很容易使类的层次结构变得复杂,也难以理解,因此无法确定究竟在类的哪一个层次结构中去增加子类。
所以,需要将“类的功能层次结构”和“类的实现层次结构”分离为两个独立的类层次结构。如果仅仅是简单的将它们分开,两者之间必然会缺乏联系,所以需要用Bridge模式搭建桥梁。

代码实例:

类的功能层次结构:Display类:

Display类的功能是抽象的,其impl字段保存了实现了Display类的具体功能的实例。该实例通过Display的构造函数被传递到Display类,然后保存在impl字段中,以供后续的处理使用。
open、print、close这三个方法分别是Display类提供的接口,其都调用了impl字段中的实现方法,将Display接口转换成为了DisplayImpl的接口。

  1. public class Display {
  2. private DisplayImpl impl;
  3. public Display(DisplayImpl impl) {
  4. this.impl = impl;
  5. }
  6. public void open(){
  7. impl.rawOpen();
  8. }
  9. public void print(){
  10. impl.rawPrint();
  11. }
  12. public void close(){
  13. impl.rawClose();
  14. }
  15. public final void display(){
  16. open();
  17. print();
  18. close();
  19. }
  20. }

类的功能层次结构:CountDisplay:

CountDisplay类再Display类的基础上增加了一个新功能。继承了Display类的三个基础方法,并使用其来增加这个新功能。

  1. public class CountDisplay extends Display{
  2. public CountDisplay(DisplayImpl impl) {
  3. super(impl);
  4. }
  5. public void multiDisplay(int times){
  6. open();
  7. for (int i = 0; i < times; i++) {
  8. print();
  9. }
  10. close();
  11. }
  12. }

类的实现层次与结构:DisplayImpl类:

这个类属于抽象类,声明了3个抽象方法。

  1. public abstract class DisplayImpl {
  2. public abstract void rawOpen();
  3. public abstract void rawPrint();
  4. public abstract void rawClose();
  5. }

类的实现层次结构:StringDisplayImpl类:

继承了DisplayImpl类,对其中的抽象方法进行实现。

  1. public class StringDisplayImpl extends DisplayImpl{
  2. private String string;
  3. private int width;
  4. public StringDisplayImpl(String string) {
  5. this.string = string;
  6. this.width = string.length();
  7. }
  8. @Override
  9. public void rawOpen() {
  10. printLine();
  11. }
  12. @Override
  13. public void rawPrint() {
  14. System.out.println("|"+string+"|");
  15. }
  16. @Override
  17. public void rawClose() {
  18. printLine();
  19. }
  20. private void printLine() {
  21. System.out.print("+");
  22. for (int i = 0; i < width; i++) {
  23. System.out.print("-");
  24. }
  25. System.out.println("+");
  26. }
  27. }

Main类:

将上述4个类进行组合,因此可以调用它们的display方法。

Bridge模式中的登场角色:

Abstraction(抽象化):

该角色位于“类的功能层次设计”最上层,使用Implementor角色的方法定义了基本的功能。该角色中保存了Implementor角色的实例。

RefinedAbstraction(改善后的抽象化):

在Abstraction角色的基础上增加了新功能的角色。

Implementor(实现者):

该角色位于“类的实现层次结构”最上层。定义了用于实现Abstraction角色功能的接口。

ConcreteImplementor(具体实现者):

该角色负责实现Implementor中定义的接口。

拓展思路的要点:

扩展性:

Bridge模式的特征是将“类的功能层次设计”和“类的实现层次结构”分离开了,将类的这两个层次结构分开更有利于独立地对它们进行扩展。
当想要增加功能的时候仅仅需要在“类的功能层次设计”一侧增加类即可,不必对“类的实现层次结构”做任何修改。而且,增加后的功能可以被“所有的实现”使用。

继承和委托:

继承是强关联,委托是弱关联。虽然使用“继承”很容易扩展类,但是类之间也形成了一种强关联关系。
如果想要很轻松地改变类之间的关系,使用继承就不太合适了,因为每次改变类之间的关系时都需要修改代码,所以可以使用“委托”来代替“继承”关系。
在上述代码中,当其他类要求Display类“工作”的时候,Display类并非是自己工作,而是将工作交给“impl”,实现委托。
只有Display的实例生成的时候,才与作为参数被传入的类构成关联。如果不传递某一实现的实例,而是更换传入的类,就可以很容易地改变实现。这个时候,发生变化的代码只有Main类,Display和DisplayImpl都不需要做任何修改。

相关的设计模式:

Template Method模式:

在Template Method中使用了“类的实现层次结构”,父类调用抽象方法,而子类实现抽象方法。

Abstract Factory模式:

能够根据需求设计出良好的具体实现者角色,有时会使用这个模式。

Adapter模式:

使用Bridge模式可以达到类的功能层次结构与类的实现层次结构分离的目的,并在此基础上使这些层次结构结合起来。
而使用Adapter模式则可以结合哪些功能上相似但是接口不同的类。