桥接模式的简单分析
1:什么是桥接
在桥接模式中,不太好理解的就是桥接的概念。什么是桥接?为何需要桥接?如何桥接?把这些问题搞清楚了,也就基本明白桥接的含义了。
一个一个来,先看看什么是桥接?所谓桥接,通俗点说就是在不同的东西之间搭一个桥,让它们能够连接起来,可以相互通讯和使用。那么在桥接模式中到底是给什么东西来搭桥呢?就是为被分离了的抽象部分和实现部分来搭桥,比如前面示例中在抽象的消息和具体消息发送之间搭个桥。
但是这里要注意一个问题,在桥接模式中的桥接是单向的,也就是只能是抽象部分的对象去使用具体实现部分的对象,而不能反过来,也就是个单向桥。
2:为何需要桥接
为了达到让抽象部分和实现部分都可以独立变化的目的,在桥接模式中,是把抽象部分和实现部分分离开来的,虽然从程序结构上是分开了,但是在抽象部分实现的时候,还是需要使用具体的实现的,这可怎么办呢?抽象部分如何才能调用到具体实现部分的功能呢?很简单,搭个桥就可以了。搭个桥,让抽象部分通过这个桥就可以调用到实现部分的功能了,因此需要桥接。
3:如何桥接
这个理解上也很简单,只要让抽象部分拥有实现部分的接口对象,就桥接上了,在抽象部分即可通过这个接口来调用具体实现部分的功能。也就是说,桥接在程序上体现了在抽象部分拥有实现部分的接口对象,维护桥接就是维护这个关系。
4:独立变化
桥接模式的意图是使得抽象和实现可以独立变化,都可以分别扩充。也就是说抽象部分和实现部分是一种非常松散的关系。从某个角度来讲,抽象部分和实现部分是可以完全分开的,独立的,抽象部分不过是一个使用实现部分对外接口的程序罢了。
如果这么看桥接模式的话,就类似于策略模式了。抽象部分需要根据某个策略,来选择真实的实现,也就是说桥接模式的抽象部分相当于策略模式的上下文。更原始的就直接类似于面向接口编程,通过接口分离的两个部分而已。但是别忘了,桥接模式的抽象部分,是可以继续扩展和变化的,而策略模式只有上下文,是不存在所谓抽象部分的。
那抽象和实现为何还要组合在一起呢?原因是在抽象部分和实现部分还是存在内部联系的,抽象部分的实现通常是需要调用实现部分的功能来实现的。
5:动态变换功能
由于桥接模式中的抽象部分和实现部分是完全分离的,因此可以在运行时动态组合具体的真实实现,从而达到动态变换功能的目的。
从另外一个角度看,抽象部分和实现部分没有固定的绑定关系,因此同一个真实实现可以被不同的抽象对象使用;反过来,同一个抽象也可以有多个不同的实现。就像前面示例的那样,比如,站内短消息的实现功能,可以被普通消息、加急消息或是特急消息等不同的消息对象使用;反过来,某个消息具体的发送方式,可以是站内短消息,或者是E-mail,也可以是手机短消息等具体的发送方式。
6:退化的桥接模式
如果Implementor仅有一个实现,那么就没有必要创建Implementor接口了,这是一种桥接模式退化的情况。这个时候Abstraction和Implementor是一对一的关系,虽然如此,也还是要保持它们的分离状态,这样的话,它们才不会相互影响,才可以分别扩展。
也就是说,就算不要Implementor接口了,也要保持Abstraction和Implementor是分离的,模式的分离机制仍然是非常有用的。
7:桥接模式和继承
继承是扩展对象功能的一种常见手段,通常情况下,继承扩展的功能变化纬度都是一纬的,也就是变化的因素只有一类。
对于出现变化因素有两类的,也就是有两个变化纬度的情况,继承实现就会比较痛苦。比如上面的示例,就有两个变化纬度,一个是消息的类别,不同的消息类别处理不同;另外一个是消息的发送方式。
从理论上来说,如果用继承的方式来实现这种有两个变化纬度的情况,最后实际的实现类应该是两个纬度上可变数量的乘积那么多个。比如上面的示例,在消息类别的纬度上,目前的可变数量是3个,普通消息、加急消息和特急消息;在消息发送方式的纬度上,目前的可变数量也是3个,站内短消息、Email和手机短消息。这种情况下,如果要实现全的话,那么需要的实现类应该是:3 × 3 = 9个。
如果要在任何一个纬度上进行扩展,都需要实现另外一个纬度上的可变数量那么多个实现类,这也是为何会感觉扩展起来很困难。而且随着程序规模的加大,会越来越难以扩展和维护。
而桥接模式就是用来解决这种有两个变化纬度的情况下,如何灵活地扩展功能的一个很好的方案。其实,桥接模式主要是把继承改成了使用对象组合,从而把两个纬度分开,让每一个纬度单独去变化,最后通过对象组合的方式,把两个纬度组合起来,每一种组合的方式就相当于原来继承中的一种实现,这样就有效地减少了实际实现的类的个数。
从理论上来说,如果用桥接模式的方式来实现这种有两个变化纬度的情况,最后实际的实现类应该是两个纬度上可变数量的和那么多个。同样是上面那个示例,使用桥接模式来实现,实现全的话,最后需要的实现类的数目应该是:3 + 3 = 6个。
这也从侧面体现了,使用对象组合的方式比继承要来得更灵活。
8:桥接模式的调用顺序示意图
桥接模式的调用顺序如图24.8所示。
(点击查看大图)图24.8 桥接模式的调用顺序示意图 |