Author:Gorit
Date:2021年2月10日
Refer:《图解设计模式》
9.1 Bridge 模式
Bridge 名为 “桥梁”
类比在现实世界当中,桥梁的功能是将河流两侧连接起来一样。
Bridge 模式的作用就是将两样东西连接起来,在两者之间架起桥梁。它们分别是:
- 类的功能层次结构
- 类的实现层次结构
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 代码
项目结构:
Display 类:
package Bridge;
import Bridge.impl.DisplayImpl;
/**
* 类的功能层次结构
* 该类的功能可以理解为抽象的,负责 ”显示一些东西“
*/
public class Display {
// 桥梁出现了,链接 Display 和 DisplayImpl
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 类
package Bridge;
import Bridge.impl.DisplayImpl;
/**
* 类的功能层次结构件
* 再 Display 的基础上增加了 规定显示次数的新功能,也就是 mutilDisplay 方法
*/
public class CountDisplay extends Display{
public CountDisplay(DisplayImpl impl) {
super(impl);
}
// 显示 num 此
public void mutiDisplay(int num) {
open();
for (int i = 1; i <= num ; i++) {
print();
}
close();
}
}
Impl.DisplayImpl
package Bridge.imp;
/**
* 桥的另一侧
* 属于类实现的层次结构
*/
public abstract class DisplayImpl {
public abstract void rawOpen();
public abstract void rawPrint();
public abstract void rawClose();
}
Impl.StringDisplayImpl
package Bridge.imp;
/**
* 属于:类的实现层次结构
*/
public class StringDisplayImpl extends DisplayImpl{
private String string; // 要显示的字符串
private int width; // 以字节单位计算出字符串的位置
public StringDisplayImpl(String string) {
this.string = string;
this.width = string.getBytes().length;
}
public void rawOpen() {
printLine();
}
public void rawPrint() {
System.out.println("|" + string + "|"); // 前后修饰 |
}
public void rawClose() {
printLine();
}
private void printLine() {
System.out.print("+"); // 用于显示方框角的 “+”
for (int i = 0; i < width ; i++) { // 作用方框的边框
System.out.print("-");
}
System.out.println("+"); // 显示用来表示方框的角的“+”
}
}
Main
package Bridge;
import Bridge.imp.StringDisplayImpl;
/**
* 将上述四个类组合起来显示字符串。
* 虽然变量 d1 中保存的是 Display 类的实例
*/
public class Main {
public static void main(String[] args) {
Display d1 = new Display(new StringDisplayImpl("Hello World"));
Display d2 = new CountDisplay(new StringDisplayImpl("Hello, Gorit"));
CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello,WuHan"));
d1.display();
d2.display();
d3.display();
d3.mutiDisplay(3);
}
}
9.2.4 运行效果
9.3 Bridge 模式中登场的角色
- Abstraction(抽象化)
- 该角色位于“类的功能层次结构”的最上层。它使用 Implementor 角色的方法定义基本的功能。该角色保存了 Implementor 角色的实例。在示例程序中,由 Display 类扮演此角色
- RefinedAbstraction(改善后的抽象化)
- 在 Abstraction 角色的基础上增加了新功能的角色。在示例程序中。由 CountDisplay 类扮演此角色
- Implementor(实现者)
- 该角色位于“类的实现层次结构”的最上层。它定义了用于实现 Abstraction 角色的接口(API)的方法。在示例程序中,DisplayImpl 类扮演此角色
- ConcreteImplementor(具体实现者)
- 该角色负责实现在 Implementor 角色中定义的接口(API)。示例程序中。由 StringDisplayImpl 类扮演此角色
9.4 拓展思路
- 分开后更容易扩展
- 继承是强关联