1、 Bridge 桥梁模式毕竟红尘 题记:原公司曾交给我一个艰巨的任务,就是在部门内推广设计模式。面对部门内众多的软件新手,在刚开始寻找切入点的时候,我有了种无法着力、一筹莫展的感觉。不过,当时恰逢央视有易老以“平民立场,现代视角”品说三国的节目,说的妙趣横生、引人入胜。于是乎灵犀一动,写了系列以“通俗立场,情爱视角”的设计模式稿子。果然,部门内关于设计模式的讨论升温了 桥梁模式并不是个使用频率很高的模式,但是它的出现,能让我们深刻地感受到前人对 OO 中各种元素流畅的驾驭能力。有人说,设计模式就像是野马,能驯服的话,会成为行走江湖的好伙伴,驯不好的话则可能伤到自己(把系统弄得乌烟瘴气) 。那么
2、,现在让我们踩着前人的肩膀,小心靠近“桥梁模式”这匹偶尔出没的野马,一起寻求驯服之道 桥梁模式的定义官方定义:桥梁模式是将抽象化与现实化脱耦,使得二者可以独立地变化。理解:说到抽象化我们自然会想到 java 中的接口(interface)和抽象类(abstract class) ,它们是 OO 软件中的上层建筑;而实现化呢,则说的是具体类,它们继承或者实现了软件“上层建筑”中规定的行为,是真正做事的角。下面描述的是大家熟悉的结构:这个结构是简单的,不过就是这样简单的结构通过各种结合方式搭在一起构成了所谓的框架和所谓的平台,所以它是 OO 中重要的机制。现在来理解下“耦合”这个概念。词霸告诉我们
3、“两个或两个以上的体系或两种运动形式之间通过各种相互作用而彼此影响以至联合起来的现象”就叫耦合。具体在 OO 中,因为一个抽象类和一个具体类通过继承这样的相互作用,所以也构成了耦合关系。人们认为,像继承这样的耦合关系是在代码编译之前就被确定下来的,该属于“强耦合”关系。那有“强”必有“弱” ,两个类或者对象通过合成关系而发生的相互作用则被称为“弱耦合” 。总言之,耦合可以理解为两个东西之间相互联系所到达的程度(哥们都还有铁不铁之分呢) 。到此为止,我们理解了定义中的这部分含义“抽象化和实现化之间,在 OO 世界里的确会很自然、很熟悉地存在所谓的耦合关系” 。紧接着,说到“脱耦” 。软件世界里,
4、有“愚民之治”一说。也就是说,如果 OO 世界里面的每个类都是一个“平民”的话,那么按这种理论要求,每个公民都应该愚昧地只知道属于自己本身的东西,而对于其它平民的东西要知道的尽可能少。这样子做的主要目的是为了减少他们之间的相互影响。或许现在我们可以合理解释“那一年大海啸后,面对众多家破人亡的印尼人民,那么多人照样还可以谈笑风生”的情景了,因为许多人认为那事情发生的遥远,和自身联系甚少(低耦合或者弱耦合) ,所以在同情之余不会让自己最本质的情感受到影响和伤害。基于这样的好处,软件里把降低模块或者类之间的关联强度(强耦合)当作一个目标,并专业地称之为“脱耦” 。试想,当某天你可以在已经存在的某个系
5、统中随心所欲地拔插一个类或一个模块而不担心影响到其它模块的时候,感觉该多么地诱人。这事情讲到这似乎出现了两难的情况了。刚开始讲到的是,正因为抽象化和现实化的联系和结合成就了 OO 的框架,现在又讲到联系和结合往往也是软件各模块互相影响和“伤害”的根源。那么我们该这样面对这样的处境呢?大禹治水的故事告诉我们,对待问题,不一定总是靠防止,以“堵”的方式来处理, “疏”往往也很有用。既然,联系是必然的,那么我们应该正确对待联系。事实上,桥梁模式就是一种处理联系的方式而已。更具体地,它告诉我们,并不需要总是用 implements 或者 extends 来处理抽象化和实现化的联系,它可以以合成的方式另
6、辟蹊径地“疏导”这种联系(这点现在感觉有点奇怪,不过等下就会发现这是完全可行的) 。至此,我们已经在帐篷内了解了“野马”的环境和脾性,现在让我们走出帐篷看看桥梁模式这匹马到底长成什么样子。桥梁模式的结构桥梁模式的结构如下:+Operation+Operation+OperationImp+OperationImp +OperationImpAbstraction ImplementationRefinedAbstraction ComcretedImplementation1AConcretedImplementation2结构中各个角色的描述如下(摘自java 与模式 ): 抽象化(Abst
7、raction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。 修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和休整父类对抽象化的定义。 实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当给出底层操作,而抽象化角色应当只给出基于底层操作更高一层的操作。 具体实现化角色:这个角色给出实现化角色接口的具体实现。对这个结构理解的支点,在于上文高频率出现的“组合”和“继承”两个词。为了更进一步说明桥梁模式把“通过继承实现的
8、抽象化与实现化的联系是可以转化为组合来实现的联系”描述清楚,现在我们来对“男孩爱女孩,爱的疯狂,爱的有味道”这样的可能现实命题建模。上帝说正常的男孩自然会喜欢女孩,这是规则。于是出现了男孩这个抽象类,在类中定义了“爱女孩”这个规则:abstract class 男孩abstract void love(女孩 某女孩);我们也知道这世界上有种特别懂得爱的男孩,他们的爱会比较有味道。我们称这类人为,情圣,他的定义如下:class 情圣 extends 男孩public void love(女孩 某女孩)某女孩.说(“的确好像很有味道但是” ); 这是用继承实现的结构,在编译前男孩与情圣的关系就确定
9、下来,所以它们是“强耦合” 。现在,我们通过桥梁模式用组合方式来实现更灵活的爱的效果。因为每个男孩都有自己爱的方式,所以我们抽象出“爱的方式”这个接口:interface 爱的方式void love(女孩 某女孩);那么,男孩和爱的方式之间的联系就可以是组合关系如下:abstract class 男孩protected 爱的方式 方式;public void love(女孩 某女孩)方式.love(某女孩);我们知道爱的方式有很多种,效果也不一样。我们现在重点说两种,一种是象情圣那样“有味道的爱” ,另外一种是“疯狂的爱” ,如下:class 有味道的爱 implements 爱的方式void
10、 love(女孩 某女孩)某女孩.说(“爱的的确有些味道但是” ) ;class 疯狂的爱 implements 爱的方式void love(女孩 某女孩)某女孩.说(“太疯狂了但是” ) ;现在再来看情圣这个角色:class 情圣 extends 男孩public void set 爱的方式(爱的方式 方式)this.爱的方式 = 方式;在上面的整个过程中,我们看得出来情圣通过,对爱的方式“委托” ,用“组合”的方式同样达到可以“爱的有味道”的结局。某人要是情圣的话,他可能会感叹爱之灵活,如下:情圣 某人 = new 情圣();某人.set 爱的方式(new 有味道的爱 ();/一段时间后,
11、女孩觉得需要更热烈更疯狂的爱某人.set 爱的方式(new 疯狂的爱 ();/love 的实现也随着改变了!“桥梁模式”的桥在于“爱的方式” ,男孩通过对爱的方式的委托(其实就是搭了个桥) ,达到在运行期改变 love 实现的效果。建议:不妨把上面的情爱过程中的角色和桥梁模式中的各个角色再做一下对应,领会一下。此刻,我们是不是已经骑在马背上了呢?关于作者:本文作者吴战胜,是国家认证软件设计师。他曾在深圳华为的业务软件部任软件工程师,目前在深圳任子行网络科技有限公司总工办任职,从事安全软件的架构以及开发。Email:联系地址:深圳市南山区软件园 2 栋 6 楼 深圳任子行网络技术有限公司邮编:518057真实姓名:吴战胜身份证号:350322198208152558