定义
- 在“类的功能层次结构”和“类的实现层次结构”之间搭建桥梁。
类的层次结构的两个作用
希望增加新功能时
- 父类具有基本功能
- 在子类中增加新的功能
以上这种层次结构被称为“类的功能层次结构”。
当要增加新的功能时,我们可以从各个层次的类中找出最符合自己需求的类,然后以它为父类编写子类,并在子类中增加新的功能。这就是“类的功能层次结构”。
希望增加新的实现时
- 父类通过声明抽象方法来定义接口(API)
- 子类通过实现具体方法来实现接口(API)
这种层次结构被称为“类的实现层次结构”。
当我们以其他方法实现AbstractClass时,例如要实现一个AnotherConcreteClass时,类的层次结构会稍微发生一些变化。
为了一种新的实现方式,我们继承了AbstractClass的子类,并实现了其中的抽象方法。这就是“类的实现层次结构”。
类的层次结构的混杂与分离
在编写子类时,需要先确认自己的意图:“我是要增加功能呢?还是要增加实现呢?”当类的层次结构只有一层时,功能层次结构与实现层次结构是混杂在一个层次结构中的。这样很容易使类的层次结构变得复杂,也难以透彻地理解类的层次结构。因为自己难以确定究竟应该在类的哪一个层次结构去增加子类。
因此需要将“类的功能层次结构”与“类的实现层次结构”分离为两个独立的类层次结构。还需要在它们之间搭建一座桥梁。
Bridge模式中的登场角色
- Abstraction(抽象化)
该角色位于“类的功能层次结构”的最上层。它使用Implementor角色的方法定义了基本的功能。该角色保存了Implementor角色的实例。
- RefinedAbstraction(改善后的抽象化)
在Abstraction角色基础上增加了新功能的角色。
- Implementor(实现者)
该角色位于“类的实现层次结构”的最上层。它定义了用于实现Abstraction角色的接口(API)的方法。
- ConcreteImplementor(具体实现者)
该角色负责实现在Implementor角色中定义的接口(API)。
Brideg模式的类图
左侧的两个类构成了“类的功能层次结构”,右侧两个类构成了“类的实现层次结构”。两个类的层次结构之间的桥梁是impl字段(采用委托方式)。
拓展思路的要点
- 分开后更容易扩展
将类的这两个层次结构分离开有利于独立地对它们进行扩展。
当想要增加功能时,只需要在“类的功能层次结构”一侧增加类即可,不必对“类的实现层次结构”做任何修改。而且,增加后的功能可以被“所有的实现”使用。
- 继承是强关联,委托是弱关联
虽然使用“继承”很容易扩展类,但是类之间也形成了一种强关联关系。
如果想要很轻松地改变类之间的关系,使用继承就不合适了,因为每次改变类之间关系时都需要修改程序。这时,我们可以使用“委托”来代替“继承”关系。
相关的设计模式
在Template Method模式中使用了“类的实现层次结构”。父类调用抽象方法,而子类实现抽象方法。
为了能够根据需求设计出良好的ConcreteImplementor角色,有时我们会使用Abstract Factory模式。
使用Bridge模式可以达到类的功能层次结构与类的实现层次结构分离的目的,并在此基础上使这些层次结构结合起来。
而使用Adapter模式则可以结合那些功能上相似但是接口(API)不同的类。
代码
- Abstraction(抽象化)
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();
}
}
- RefinedAbstraction(改善后的抽象化)
public class CountDisplay extends Display {
public CountDisplay(DisplayImpl impl) {
super(impl);
}
// 增加功能(功能层次结构)
public void multiDisplay(int times) { // 循环显示times次
open();
for (int i = 0; i < times; i++) {
print();
}
close();
}
}
- Implementor(实现者)
public abstract class DisplayImpl {
public abstract void rawOpen();
public abstract void rawPrint();
public abstract void rawClose();
}
- ConcreteImplementor(具体实现者)
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.print("-");
}
System.out.println("+");
}
}
- Main类
public class Main {
public static void main(String[] args) {
Display d1 = new Display(new StringDisplayImpl("Hello, China."));
Display d2 = new CountDisplay(new StringDisplayImpl("Hello, World."));
CountDisplay d3 = new CountDisplay(new StringDisplayImpl("Hello, Universe."));
d1.display();
d2.display();
d3.display();
d3.multiDisplay(5);
}
}
注:博客中的图片来自网上。