??????? 使用Java编写程序,一个很重要的原则就是“面向接口编程”,说得准确点应该是“面向抽象编程”,由于在Java开发中,更多的使用接口而非抽象类,因此通常就说成“面向接口编程”了。
??????? 接口把具体的实现和使用接口的客户程序分离开来,从而使得具体的实现和使用接口的客户程序可以分别扩展,而不会相互影响。使用接口的程序结构如图12所示:
???????????????????????? ?图12? 使用接口的程序结构示意图
??????? 可能有些朋友会觉得,听起来怎么像是桥接模式的功能呢?没错,如果把桥接模式的抽象部分先稍稍简化一下,暂时不要RefinedAbstraction部分,那么就跟上面的结构图差不多了。去掉RefinedAbstraction后的简化的桥接模式结构示意图如图13所示:
?????????????? ?图13? 简化的桥接模式结构示意图
??????? 是不是差不多呢?有朋友可能会觉得还是有很大差异,差异主要在:前面接口的客户程序是直接使用接口对象,不像桥接模式的抽象部分那样,是持有具体实现部分的接口,这就导致画出来的结构图,一个是依赖,一个是聚合关联。
??????? 请思考它们的本质功能,桥接模式中的抽象部分持有具体实现部分的接口,最终目的是什么,还不是需要通过调用具体实现部分的接口中的方法,来完成一定的功能,这跟直接使用接口没有什么不同,只是表现形式有点不一样。再说,前面那个使用接口的客户程序也可以持有相应的接口对象,这样从形式上就一样了。
??????? 也就是说,从某个角度来讲,桥接模式不过就是对“面向抽象编程”这个设计原则的扩展。正是通过具体实现的接口,把抽象部分和具体的实现分离开来,抽象部分相当于是使用实现部分接口的客户程序,这样抽象部分和实现部分就松散耦合了,从而可以实现相互独立的变化。
??????? 这样一来,几乎可以把所有面向抽象编写的程序,都视作是桥接模式的体现,至少算是简化的桥接模式,就算是广义的桥接吧。而Java编程很强调“面向抽象编程”,因此,广义的桥接,在Java中可以说是无处不在。
??????? 再举个大家最熟悉的例子来示例一下。在Java应用开发中,分层实现算是最基本的设计方式了吧,就拿大家最熟的三层架构来说,表现层、逻辑层和数据层,或许有些朋友对它们称呼的名称不同,但都是同一回事情。
三层的基本关系是表现层调用逻辑层,逻辑层调用数据层,通过什么来进行调用呢?当然是接口了,它们的基本结构如图14所示:
????????? ?图14? 基本的三层架构示意图
??????? 通过接口来进行调用,使得表现层和逻辑层分离开来,也就是说表现层的变化,不会影响到逻辑层,同理逻辑层的变化不会影响到表现层。这也是同一套逻辑层和数据层,就能够同时支持不同的表现层实现的原因,比如支持Swing或Web方式的表现层。
??????? 在逻辑层和数据层之间也是通过接口来调用,同样使得逻辑层和数据层分离开,使得它们可以独立的扩展。尤其是数据层,可能会有很多的实现方式,比如:数据库实现、文件实现等,就算是数据库实现,又有针对不同数据库的实现,如Oracle、DB2等等。
??????? 总之,通过面向抽象编程,三层架构的各层都能够独立的扩展和变化,而不会对其它层次产生影响。这正好是桥接模式的功能,实现抽象和实现的分离,从而使得它们可以独立的变化。当然三层架构不只是在一个地方使用桥接模式,而是至少在两个地方来使用了桥接模式,一个在表现层和逻辑层之间,一个在逻辑层和数据层之间。
??????? 下面先分别看看这两个使用桥接模式的地方的程序结构,然后再综合起来看看整体的程序结构。先看看逻辑层和数据层之间的程序结构,如图15所示:
???????????? ?图15? 逻辑层和数据层的程序结构示意图
?再看看表现层和逻辑层之间的结构示意,如图16所示:
???? ?图16? 表现层和逻辑层的结构示意图
?然后再把它们结合起来,看看结合后的程序结构,如图17所示:
??????????????????????????? ?图17? 三层结合的结构示意图
??????? 从广义桥接模式的角度来看,平日熟悉的三层架构其实就是在组合使用桥接模式。从这个图还可以看出,桥接模式是可以连续组合使用的,一个桥接模式的实现部分,可以作为下一个桥接模式的抽象部分。如此类推,可以从三层架构扩展到四层、五层、直到N层架构,都可以使用桥接模式来组合。
??????? 如果从更本质的角度来看,基本上只要是面向抽象编写的Java程序,都可以视为是桥接模式的应用,都是让抽象和实现相分离,从而使它们能独立的变化。不过只要分离的目的达到了,叫不叫桥接模式就无所谓了。
1:桥接模式的本质
??????? 桥接模式的本质:分离抽象和实现。
??????? 桥接模式最重要的工作就是分离抽象部分和实现部分,这是解决问题的关键。只有把抽象和实现分离开了,才能够让它们可以独立的变化;只有抽象和实现可以独立的变化,系统才会有更好的可扩展性、可维护性。
??????? 至于其它的好处,比如:可以动态切换实现、可以减少子类个数等。都是把抽象部分和实现部分分离过后,带来的,如果不把抽象部分和实现部分分离开,那就一切免谈了。所以综合来说,桥接模式的本质在于“分离抽象和实现”。
2:对设计原则的体现
(1)桥接模式很好的实现了开闭原则。
??????? 通常应用桥接模式的地方,抽象部分和实现部分都是可变化的,也就是应用会有两个变化纬度,桥接模式就是找到这两个变化,并分别封装起来,从而合理的实现OCP。
??????? 在使用桥接模式的时候,通常情况下,顶层的Abstraction和Implementor是不变的,而具体的Implementor的实现,是可变的,由于Abstraction是通过接口来操作具体的实现,因此具体的Implementor的实现是可以扩展的,根据需要可以有多个具体的实现。
??????? 同样的,RefinedAbstraction也是可变的,它继承并扩展Abstraction,通常在RefinedAbstraction的实现里面,会调用Abstraction中的方法,通过组合使用来完成更多的功能,这些功能常常是与具体业务有关系的功能。
??????? 桥接模式还很好的体现了:多用对象组合,少用对象继承。
??????? 在前面的示例中,如果使用对象继承来扩展功能,不但让对象之间有很强的耦合性,而且会需要很多的子类才能完成相应的功能,前面已经讲述过了,需要两个纬度上的可变化数量的乘积个子类。
??????? 而采用对象的组合,松散了对象之间的耦合性,不但使每个对象变得简单和可维护,还大大减少了子类的个数,根据前面的讲述,大约需要两个纬度上的可变化数量的和这么多个子类。
3:何时选用桥接模式
??????? 建议在如下情况中,选用桥接模式:
?
?
?
?
?
?研磨设计模式结束,谢谢捧场!?