Author:Gorit
Date:2021年2月10日
Refer:《图解设计模式》

9.1 Bridge 模式

Bridge 名为 “桥梁”
类比在现实世界当中,桥梁的功能是将河流两侧连接起来一样。

Bridge 模式的作用就是将两样东西连接起来,在两者之间架起桥梁。它们分别是:

  1. 类的功能层次结构
  2. 类的实现层次结构

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

◇ 希望增加新功能时

假如现在有一个类 Something。我们要在 Something 中增加新功能(增加一个具体的方法)。会编写 Something 类的子类(派生类),即 SomethongGood 类。这样就形成了一个小小的层次结构

Something

  • SomethingGood

这就是为了增加新功能而产生的层次结构

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

这就是 类的层次结构

PS:类的层次结构不应该过深

当我们还想继续增加功能时,同理,我们可以编写一个 SomethingBetter 类的子类,即 SomethingBetter 类。这样 类的层次结构就体现的更加深刻了
Something

  • SomethingGood
    • SomethingBetter

因此,当要增加新功能时,我们可以从各个层次的类中找出最符合自己需求的类,然后以它为父类编写子类,并在子类增加功能。这就是 类的功能层次结构

◇ 希望增加新的实现

在 Template Method 模式中,我们学习了抽象类的作用。抽象类声明了一些抽象方法,定义了接口(API),然后子类负责实现这些接口。父类的任务是通过声明抽象方法的方式定义接口(API)。子类的任务则是负责实现 父类的接口。正式由于 父类和子类的这种任务分担,我们才可以编写具有高可替换的类。

这里也存在“层次”的关系,比如子类 ConcreteClass 实现了 父类 AbstractClass 类的抽象方法,他们之间就构成了一种“层次”关系
AbstractClass

  • ConcreteClass

但是,这里类的层次结构并非用于增加功能,也就是说,这种层次结构并非用于方便我们增加新的方法。它的真正作用是帮助我们实现下面这样的任务分担

  • 父类通过声明抽象方法来定义接口(API)
  • 子类通过实现具体的方法来定义接口(API)

这种层次结构被称为:“类的实现层次结构”
当我们以其他方式实现 AbstractClass 时,例如要实现一个 AnotherConcreteClass 时,类的层次结构变成了这样

AbstractClass

  • ConcreteClass
  • AnotherConcreteClass

为了一种新的实现方式,我们继承了 AbstractClass 的子类,并实现了其中的抽象方法,这就是类的实现层次结构

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

当然也会存在这样一种情况,当我们要编写一个子类时,我们是“增加功能”呢? 还是“增加实现”呢?这样就很容易使一个类变得极为复杂。

因此,我们要将“类的功能层次结构” 与 “类的实现层次结构”分离成两个独立的层次结构

9.2 示例程序

9.2.1 程序功能

显示一些“东西”

9.2.2 程序结构

在桥的哪一侧 类名 功能说明
类的功能的层次结构 Display 负责“显示”的类
类的功能的层次结构 CountDisplay 增加了“只显示规定次数”这一功能的类
类的实现层次结构 DisplayImpl 负责“显示”的类
类的实现层次结构 StringDisplayImpl “用字符串显示”的类
Main 测试程序行为的类

9.2.3 代码

项目结构:
image.png

Display 类:

  1. package Bridge;
  2. import Bridge.impl.DisplayImpl;
  3. /**
  4. * 类的功能层次结构
  5. * 该类的功能可以理解为抽象的,负责 ”显示一些东西“
  6. */
  7. public class Display {
  8. // 桥梁出现了,链接 Display 和 DisplayImpl
  9. private DisplayImpl impl;
  10. public Display(DisplayImpl impl) {
  11. this.impl = impl;
  12. }
  13. // 显示前的处理
  14. public void open() {
  15. impl.rawOpen();
  16. }
  17. // 显示处理
  18. public void print() {
  19. impl.rawPrint();
  20. }
  21. // 显示后的处理
  22. public void close() {
  23. impl.rawClose();
  24. }
  25. public final void display () {
  26. open();
  27. print();
  28. close();
  29. }
  30. }

CountDisplay 类

  1. package Bridge;
  2. import Bridge.impl.DisplayImpl;
  3. /**
  4. * 类的功能层次结构件
  5. * 再 Display 的基础上增加了 规定显示次数的新功能,也就是 mutilDisplay 方法
  6. */
  7. public class CountDisplay extends Display{
  8. public CountDisplay(DisplayImpl impl) {
  9. super(impl);
  10. }
  11. // 显示 num 此
  12. public void mutiDisplay(int num) {
  13. open();
  14. for (int i = 1; i <= num ; i++) {
  15. print();
  16. }
  17. close();
  18. }
  19. }

Impl.DisplayImpl

  1. package Bridge.imp;
  2. /**
  3. * 桥的另一侧
  4. * 属于类实现的层次结构
  5. */
  6. public abstract class DisplayImpl {
  7. public abstract void rawOpen();
  8. public abstract void rawPrint();
  9. public abstract void rawClose();
  10. }

Impl.StringDisplayImpl

  1. package Bridge.imp;
  2. /**
  3. * 属于:类的实现层次结构
  4. */
  5. public class StringDisplayImpl extends DisplayImpl{
  6. private String string; // 要显示的字符串
  7. private int width; // 以字节单位计算出字符串的位置
  8. public StringDisplayImpl(String string) {
  9. this.string = string;
  10. this.width = string.getBytes().length;
  11. }
  12. public void rawOpen() {
  13. printLine();
  14. }
  15. public void rawPrint() {
  16. System.out.println("|" + string + "|"); // 前后修饰 |
  17. }
  18. public void rawClose() {
  19. printLine();
  20. }
  21. private void printLine() {
  22. System.out.print("+"); // 用于显示方框角的 “+”
  23. for (int i = 0; i < width ; i++) { // 作用方框的边框
  24. System.out.print("-");
  25. }
  26. System.out.println("+"); // 显示用来表示方框的角的“+”
  27. }
  28. }

Main

  1. package Bridge;
  2. import Bridge.imp.StringDisplayImpl;
  3. /**
  4. * 将上述四个类组合起来显示字符串。
  5. * 虽然变量 d1 中保存的是 Display 类的实例
  6. */
  7. public class Main {
  8. public static void main(String[] args) {
  9. Display d1 = new Display(new StringDisplayImpl("Hello World"));
  10. Display d2 = new CountDisplay(new StringDisplayImpl("Hello, Gorit"));
  11. CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello,WuHan"));
  12. d1.display();
  13. d2.display();
  14. d3.display();
  15. d3.mutiDisplay(3);
  16. }
  17. }

9.2.4 运行效果

image.png

9.3 Bridge 模式中登场的角色

  • Abstraction(抽象化)
    • 该角色位于“类的功能层次结构”的最上层。它使用 Implementor 角色的方法定义基本的功能。该角色保存了 Implementor 角色的实例。在示例程序中,由 Display 类扮演此角色
  • RefinedAbstraction(改善后的抽象化)
    • 在 Abstraction 角色的基础上增加了新功能的角色。在示例程序中。由 CountDisplay 类扮演此角色
  • Implementor(实现者)
    • 该角色位于“类的实现层次结构”的最上层。它定义了用于实现 Abstraction 角色的接口(API)的方法。在示例程序中,DisplayImpl 类扮演此角色
  • ConcreteImplementor(具体实现者)
    • 该角色负责实现在 Implementor 角色中定义的接口(API)。示例程序中。由 StringDisplayImpl 类扮演此角色

9.4 拓展思路

  1. 分开后更容易扩展
  2. 继承是强关联