1 意图
将抽象部分与它的实现部分分离,使它们都可以独立的变化。
2 别名
Handle/Body
3 动机
当一个抽象可能有多个实现时,通常用继承来协调它们。抽象定义对该抽象的接口,而具体的子类则用不同的方式加以实现。但是此方法有时不够灵活。继承机制将抽象部分与它的实现部分固定在一起,使得难以对抽象部分和实现部分独立地进行修改、扩充和重用。
让我们考虑在一个用户界面箱中,一个可移植的Windo抽象实现。例如,这一抽象部分应该允许用户开发一些X Window System和IBM的Presentation Manager(PM)系统中都可以使用的应用程序。运用继承机制,我们可以定义Window抽象类和它的两个子类Xwindow和PMWindow,由它们分别实现不同系统平台的Window界面。但是继承机制有两个不足之处:
-
1 扩展Window抽象使之适用于不同种类的窗口或新的系统平台很不方便。假设有Window的一个子类IconWindow,它专门将Window抽象于图标处理。为了使IconWindow支持两个系统平台,我们必须实现两个新类XIconWindow和PMIIconWindow,更为糟糕的是,我们不得不为每一种类型的窗口都定义两个类,而为了支持第三个系统平台我们还必须为每一种窗口定义一个新的Window子类,如下图所示
- 2 继承机制使得客户代码与平台相关。每当客户创建一个窗口,必须要实例化一个具体的类,这个类有特定的实现部分。例如,创建XWindow对象将Window抽象与XWindow的实现部分绑定起来,这使得客户程序依赖于XWindow的实现部分。这将使得很难将客户代码移植到其它平台上去。
客户在创建窗口应该不涉及到其具体实现部分,仅仅是窗口的实现部分依赖于应用运行的平台。这样客户代码在创建窗口就不应涉及到特定的平台。
Bridge 模式解决以上的方法是,将Window抽象和它的实现部分分别放在独立的类层次结构中。其中一个类层次结构针对窗口接口,另外一个独立的类层次结构针对平台相关的接口实现部分,这个类层次结构的根类为WindowImp。例如XWindowImp子类提供了一个基于XWindow系统的实现,如下图所示:
对Window子类的所有操作都是用WindowImp的接口中的抽象操作实现的,这就将窗口的抽象和系统平台相关的实现部分分离开来。因此,我们将Window与WindowImp之间的关系称之为桥接,因为它在抽象类与它的实现之间起到了桥梁作用,使它们可以独立地变化。
4. 适应性
以下情况使用Bright模式:
- 1 你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换;
- 类的抽象以及它的实现都可以通过生成子类的方法加以扩充,这时Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们扩充;
- 3 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译;
- 4 (C + +)你想对客户完全隐藏抽象的实现部分。在 C + +中,类的表示在类接口中是可见的;
- 5 正如在意图一节的第一个类图中所示的那样,有许多类要生成。这样一种类层次结构说明你必须将一个对象分解成两个部分;
- 6 你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并不知道这一点。
5 结构
6 参与者
- Abstraction(Window)
——定义抽象类的接口
——维护一个指向Implemtor类型对象的指针 - RefinedAbstraction(IconWindow)
——扩充由Abstraction定义的接口 - Implementor(WindowImp)
——定义实现类的接口,该接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作; - ConcreteImplementor(XWindowImp,PMWindowImp)
——实现Implementor接口并定义它的具体实现
7 协作
- Abstraction将client的请求转发给它的Implementor对象
8 效果
Bridge模式有以下的一些优点:
- 1 分离接口和实现部分
- 2 提供可扩充性
- 3 实现细节对客户的透明
9 实现
要注意的问题:
- 1 在仅有一个实现的时候,没有必要创建一个抽象的Implementor类
- 2 创建正确的Implementor对象
- 3 共享Implementor对象
- 4 采用多重继承机制