Bridge 模式定义
意图
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
动机
让我们考虑在一个用户界面工具箱中,一个可移植的Window 抽象部分的实现。例如,这一抽象部分允许 Client 开发一些在 X Window System 和 IBM 的 PM(Presentation Manager)系统中都可以使用的 App。如果这里我们运用继承机制,比如定义 Window 抽象类和它的两个子类 XWindow 与 PMWindow,由它们分别实现不同系统平台上的 Window 界面。但继承机制有几点不足:
- 扩展 Window 抽象使之适用于不同种类的窗口或新的系统平台很不方便。假如有一个 Window 子类 IconWindow,它专门将 Window 抽象用于图标处理。为了使 IconWindow 支持两个系统平台,我们必须实现两个新类 XIconWindow 和 PMIconWindow 如下(对比 Bridge 模式之后可以感觉到此继承设计的愚蠢):
![053b1ca4b0cec73b1caf59adfe31cf1e.png](https://img-blog.csdnimg.cn/img_convert/053b1ca4b0cec73b1caf59adfe31cf1e.png)
如果后续为了支持第三个系统平台我们还必须为每一种窗口定义一个新的 Window 子类。
- 继承机制使得 Client 代码与平台相关。每当 Client 创建一个窗口时,必须要实例化一个具体的类,这个类有特定的实现部分。
Bridge 模式就用于解决以上问题的,我们直接看图:
![de1fde0bcf34f33436f63088ba4bc70c.png](https://img-blog.csdnimg.cn/img_convert/de1fde0bcf34f33436f63088ba4bc70c.png)
将窗口的抽象与系统平台相关的实现部分分离开来。因此,我们将 Window 与 WindowImp 之间的关系称之为桥接,因为它在抽象类与它的实现之间起到了桥梁作用,使它们可以独立地变化。
结构
![1f8039c9ec020bcfb772ac66ea6e95c2.png](https://img-blog.csdnimg.cn/img_convert/1f8039c9ec020bcfb772ac66ea6e95c2.png)
代码示例
下面的 C++代码实现了 Window / WindowImp 的例子,其中 Window 类为 Client App 定义了窗口抽象类:
![f677caa7b6d133ed7ef35eb9ddce5776.png](https://img-blog.csdnimg.cn/img_convert/f677caa7b6d133ed7ef35eb9ddce5776.png)
Window 类维护了一个对 WindowImp 的引用。
WindowImp 抽象类定义了一个对底层窗口系统的接口:
![14199f0eb13f1b2ac56b717a4ce7a276.png](https://img-blog.csdnimg.cn/img_convert/14199f0eb13f1b2ac56b717a4ce7a276.png)
WindowImp 抽象类
Window 的子类定义了 App 可能会用到的不同类型的窗口,如应用窗口、图标、对话框临时窗口以及工具箱的移动面板等等。例如 ApplicationWindow 类将实现 DrawContents 操作以绘制它所存储的 View 实例:
![f813ac17da307a983e33b332f25710c4.png](https://img-blog.csdnimg.cn/img_convert/f813ac17da307a983e33b332f25710c4.png)
ApplicationWindow 类
IconWindow 中存储了它所显示的图标对应的位图名,并且实现 DrawContents 操作将这个位图绘制于窗口上:
![e71e544a718fb3e883a95bd5174e94e4.png](https://img-blog.csdnimg.cn/img_convert/e71e544a718fb3e883a95bd5174e94e4.png)
IconWindow 类
Window 的操作由 WindowImp 的接口定义。例如,在调用 WindowImp 操作在窗口中绘制矩形之前,DrawRect 必须从它的两个 Point 参数中提取四个坐标值:
![0033590fb8125b2a462e507c09441d5c.png](https://img-blog.csdnimg.cn/img_convert/0033590fb8125b2a462e507c09441d5c.png)
具体的 WindowImp 子类可支持不同的窗口系统:
![617b1811b028003dfd4b2a4aa7be55cd.png](https://img-blog.csdnimg.cn/img_convert/617b1811b028003dfd4b2a4aa7be55cd.png)
XwindowImp 子类支持 X Window 窗口系统。
![5cdfaa5742eac380b88f3ad335a46d0d.png](https://img-blog.csdnimg.cn/img_convert/5cdfaa5742eac380b88f3ad335a46d0d.png)
Presentation Manager
那么一个窗口怎样得到正确的 WindowImp 子类的实例呢?本例中由 Window 类负责,它的 GetWindowImp 操作负责从一个抽象工厂得到正确的实例,这个抽象工厂封装了所有窗口系统的细节:
![46703c9dfcd77c7fb3e4bba676ea7ef3.png](https://img-blog.csdnimg.cn/img_convert/46703c9dfcd77c7fb3e4bba676ea7ef3.png)
为简化起见,我们将它创建一个单件,允许 Window 类直接访问这个工厂。
参考文献
《 设计模式:可复用面向对象软件的基础 》Erich Gamma Richard Helm Ralph JohnsonJohn Vlissides 著。