本文中涉及到的完整代码存放于以下 GitHub 仓库中 LearningCode
1. 理论部分
桥接模式(Bridge Pattern):将抽象部分与它的实现部分解耦,使得两者都能够独立变化。
桥接模式也被称为柄体模式(Handle and Body Pattern)或接口模式(Interface Pattern)。
1.1 结构与实现
桥接模式包含以下 4 个角色:
- Abstraction(抽象类):
- 职责:定义抽象类的接口,维护一个指向 Implementor 类型对象的指针。
- 实现:Abstraction 通常声明为抽象类而不是接口。
- RefinedAbstraction(扩充抽象类):
- 职责:实现 RefinedAbstraction 中定义的接口。
- 实现:RefinedAbstraction 通常声明为具体类。
- Implementor(实现类接口):
- 职责:定义实现类的接口,该接口不一定要与 Abstraction 的接口完全一致,事实上这两个接口可以完全不同。一般来讲,Implementor 接口仅提供基本操作,而 Abstraction 则定义了基于这些基本操作的较高层次的操作。
- 实现:Implementor 通常声明为接口或抽象类。
- ConcreteImplementor(具体实现类):
- 职责:实现 ConcreteImplementor 中定义的接口。
- 实现:ConcreteImplementor 通常声明为具体类。
桥接模式的 UML 类图如下所示:
1.2 优缺点与适用场景
桥接模式具有以下优点:
- 分离抽象接口及其实现关系。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。
- 桥接模式提高了系统的可扩展性,在两个变化维度中任意扩展一个维度都不需要修改原有系统,符合开闭原则。
- 减少子类的数量。在很多情况下,桥接模式可以取代多层继承方案,多层继承方案违背了单一职责原则,复用性较差,并且类的个数非常多,桥接模式是比多层继承方案更好的解决方案,它极大地减少了子类的个数。
桥接模式存在以下缺点:
- 桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
- 桥接模式要求正确地识别出系统中的两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。
桥接模式适用于以下场景:
- 如果一个系统需要在抽象化和具体化之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- 抽象部分和实现部分可以用继承的方式独立扩展而互不影响,在程序运行时可以动态地将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
- 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
- 对于那些不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
2. 实现部分
以 Java 代码为例,演示桥接模式的实现。
案例介绍:
编写抽象类 —— Image
public abstract class Image {
protected ImageImp imp;
public void setImp(ImageImp imp) {
this.imp = imp;
}
public abstract void parseFile(String fileName);
}
编写扩展实现类,以 PNGImage 为例:
public class PNGImage extends Image{
@Override
public void parseFile(String fileName) {
Matrix m = new Matrix();
imp.doPaint(m);
System.out.println(fileName + ", 格式为 PNG.");
}
}
编写实现类接口 —— ImageImp
public interface ImageImp {
void doPaint(Matrix m);
}
编写具体实现类,以 WindowsImp 为例
public class WindowsImp implements ImageImp{
@Override
public void doPaint(Matrix m) {
System.out.print("在 Windows 操作系统中显示图像:");
}
}
客户端调用:
public class Main {
public static void main(String[] args) {
// 可以使用配置文件来优化 Image、WindowsImp 实例的获取
Image image = new JPGImage();
WindowsImp windowsImp = new WindowsImp();
image.setImp(windowsImp);
image.parseFile("小龙女");
}
}
完整的 UML 类图如下所示:
3. 参考资料
学习视频:
- 设计模式快速入门 —— 图灵星球TuringPlanet —— 桥接模式
- Java设计模式详解 —— 黑马程序员 —— 桥接模式(P75 ~ P77)
- Java设计模式 —— 尚硅谷 —— 桥接模式(P66 ~ P70)
学习读物:
- 《设计模式:可复用面向对象软件的基础》—— Erich Gamma 著 —— 李英军 译 —— 第 4.2 节(P115)
- 《Java 设计模式》 —— 刘伟 著 —— 第 10 章(P133)
- 《设计模式之美》—— 王争 著 —— 第 7.4 节(P230)
- 《设计模式之禅》 —— 第 2 版 —— 秦小波 著 —— 第 29 章(P371)
- 《图解设计模式》—— 结城浩 著 —— 杨文轩 译 —— 第 9 章(P93)
电子文献: