序
桥接模式是一种结构性设计模式,它将抽象与实现相分离,使得他们都可以独立的变化
动机和结构
作为传统的面向对象编程,当一个抽象接口可能有多个实现时,最简单的做法是声明一个接口基类,然后子类实现接口。但这样在一些场景下会有明显的缺点。试想这样一种场景。在一个用户界面工具箱中,一个可移植的窗口抽象部分的实现。在这个场景中,简单的继承方式的缺点如下:
- 扩展Window抽象使之适用于不同种类的窗口或新的系统平台很不方便。假设 Window 接口需要一个子类接口 IconWindow,而这两个接口都需要支持两个平台。那么类结构就会出现下图所示的情况,如果需要再支持另外一个平台,结构就更加臃肿。
- 继承机制使得客户代码与平台相关。用户必须去实例化一个具体的Window类,而这个类肯定有其特有的实现部分。这使得客户可能会去依赖这些特有的部分,导致代码难以移植。
桥接模式正是为解决上述的问题而出现的。桥接模式将 Window 抽象和它的实现部分分别放在独立的类层次结构中。其中一个类层次结构针对窗口接口(Window),另外一个独立的类层次结构针对平台相关的窗口实现部分(WindowImp)。对Window子类的所有操作都是用 WindowImp接口中的抽象操作实现的。
使用时机
- 不希望在抽象和它的实现部分之间有一个固定的绑定关系。
- 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。
- 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
- (C++)你想对客户完全隐藏抽象的实现部分。在 C++中,类的表示在类接口中是可见的。
- 如动机中的类图所示,有许多类要生成。这样一种类层次结构说明你必须将一个对象分解成两个部分。
- 你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。
工作方法
组件
- Abstraction (Window): 定义抽象类的接口。维护一个指向Implementor类型对象的指针。
- RefinedAbstraction (IconWindow): 扩充由Abstraction定义的接口。
- Implementor (WindowImp): 定义实现类的接口,该接口不一定要与 Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲, Implementor接口仅提供基本操作,而 Abstraction则定义了基于这些基本操作的较高层次的操作。
- ConcreteImplementor(XwindowImp, PMWindowImp): 实现Implementor接口并定义它的具体实现。
协作
Abstraction将client的请求转发给它的Implementor对象。
优缺点
优点
- 分离接口及其实现部分, 将Abstraction与Implementor分离有助于降低对实现部分编译时刻的依赖性。另外,接口与实现分离有助于分层,从而产生更好的结构化系统
- 提高可扩充性, 可以独立地对Abstraction和Implementor层次结构进行扩充
- 实现细节对客户透明
缺点
- 暂无
实现要点
- 仅有一个Implementor,有必要创建一个抽象的 Implementor类。
- 创建正确的Implementor对象的方法。
- 在Abstraction的构造函数中决定。这需要Abstraction知道所有的 ConcreteImplementor。链表的实现可以用于较小的collection类,而hash表则可用于较大的collection类。
- 首先选择一个缺省的实现,然后根据需要改变这个实现
- 代理给另一个对象,由它一次决定。