Design Pattern – Bridge Pattern
1 前言
在网上查了一些Bridge Pattern的中文文章,感觉写的都是很笼统、很抽象,无法通过那些文章掌握Bridge的精髓。不过,在英文资料里面找到了一些可贵的观点,觉得有必要写点东西与大家分享。
2 介绍
从概念上说,Bridge Pattern就是用来把抽象和实现分离的桥模式。这样的定义在网上到处都是,概念中的抽象是什么,实现又是什么呢?可能你会说实现就是构造抽象、将它实例化、将它付诸于具体的行为。那么我会问:“到底如何将一个抽象从实现它的诸多方法中分离出来呢?”。这么看上去Bridge很想Adapter,Adapter的目的是为了是多个类的接口看起来像一个特定的类。而Bridge的目的是将实现从接口中分离,这样在替换了实现部分时不需要更改客户代码。
如果不明白没有关系,Bridge Pattern是设计模式中最难理解的模式之一,因为它的功能太过强大。
3 Bridge Pattern之前
在学习Bridge Pattern之前,我先举一个通俗的例子,这个例子可能过于简单,但是你可以把遇到的实际情况设想成与这个例子中所阐述的感念相同的情况。考虑一下两点:
Ø 在抽象层面的变化
Ø 这些变化如何去实现
在用户提出需求之后,作为一个程序设计者应当更早的去考虑“多变性”。也就是要考虑设计出的模型能否适应这种多变,如果可以说明你已经设计出了鲁棒、可扩展的模型;如果不可以就要考虑改变自己的设计。
试想我们有这么一种需求,写一个程序需要通过两种方法画图形。一种方法称之为(MT1),另一种方法叫(MT2)。需要画的图形包括线和圆。对应的两种方法如下表:
|
|
|
画线 | Draw_a_line | Drawline |
画园 | Draw_a_circle | Drawcircle |
客户不需要关心这两种方法的实现,他只需要知道使用了什么方法,所以我设计了一个Rectangle类和它的两个子类,这两个子类分别使用的不同的方法来绘制图形。如下图所示:
V1Rectangle和V2Rectangle继承自Rectangle,分别表示两种不同的版本。它们都重写了父类的drawLine()方法,在改方法中有分别使用了MT1和MT2两种绘画方法。
我使用了简单的树形结构来设计我的模型,现在需要改模型增加一种支持Circle画法。很自然的,我会用Shape类作为客户使用的对象并增加一层类图,如下所示:
在该图中一共有4层类,第一层是和客户打交道的Shape抽象类,客户通过它来绘制图形,具体用哪种方法客户不需要关系,全部隐藏在Shape的子类中。第二层是支持的抽象形状,它们分别有两个子类,即第三层。这层的类主要是调用了具体的画法函数(第四层)。这种设计可以通过修改第三层的代码来切换不同画法,客户不受任何影响。但是它并不是一个好的设计模型,主要有一下两点不足:
Ø 设想如果我们添加了一种新的画法(MT3),那么第三层的类会增加到6个(两中形状乘以三个方法)。
Ø 设想如果我们的模型又需要支持另一种形状,如椭圆,那么第三层的类个数会增加到9个(三种形状乘以三个方法)。
导致这种低扩展性的原因主要是因为我们没有解耦抽象与实现。他们被紧密的结合在一起。
4 Bridge Pattern之后
这里我将引出Bridge Pattern的方法,它的主要目的就是要把抽象和该抽象的诸多实现解耦。在设计第一步就要提取出需求中的抽象和实现是哪些,在我们的模型中,抽象就是形状,实现就是画法、即构造形状的方法。如下图所示:
分离出抽象和实现之后,就要建立它们之间的关系。现在有两种选择,是形状使用画法、还是画法使用形状?如下图所示:
如果我认为是画法使用形状,那么画法就需要知道形状的一些细节,如它是什么,它是什么样子等。这就违背了一条原则:一个对象只需要关系与它自己相关的东西。
再考虑形状使用画法的方式。一个形状,它不需要知道自己用了哪个画法对象,因为它只是有一个画法对象的引用。它只需调用画法函数。通过画法来构造自己。最后的类图如下所示:
这种模式分离了抽象和实现,给我们很大的自由来隐藏抽象的实现。在此基础上,如果增加了新的形状或新的画法都不会影响整个类的结构。只需要在左边(如果增加形状)或在右边(如果增加了画法)创建新的形状或画法类,让他们继承自各自的抽象类即可。
5 总结
我秉承了“One rule,One place”原则,它是实现策略的重要原则。一旦你定义了一个规则,这需要实习它一次。这样可以避免重复代码,而且如果需要修改只该一个地方即可。上例中,Shape的draw()方法只是直接的调用了Drawing的drawLine()方法,而不论Shape保持的是哪个Drawing对象。
在使用Bridge时,通常会结合其他的设计模式。比如上例中就结合了Adapter模式。
个人认为,Bridge是比较复杂、功能强大的设计模式,希望大家今后在使用时逐步的发现它的功能,做出鲁棒的模式。
此文仅代表个人观点,如有不到之处敬请谅解,有问题希望与我交流:youhaodeyi@gmail.com.