[菜鸟白话设计模式系列] Bridge 模式 一个连接线,两个支撑点

 

    小孩子在5,6岁的时候是很有创造力和想像力的,而且很喜欢"跟风",看见邻居家小孩买了新的玩具,一定要嚷嚷着父母给买一个.父母坳不过就买吧,今天一辆小汽车,明天一个大房子,于是乎没完没了了,几个月下来小孩子屋里全是玩具.

    有一天父母给他买了一套积木,可把小孩给乐的,每天在屋子里不停的摆停着,一会组装个小桥,一会组装个小汽车出来,玩的不亦乐乎啊,从此父母得到了消停.

    看来现在的大人们早已深知组合的魅力啊!孩子们呢从组合中开发了思维,又乐在其中.

    今天讲的Bridge模式就是通过一个组合的技术给你一个解决子类膨胀的漂亮方案.

    Bridge模式的实现非常简单,就是通过组合的方式达到给抽象和具体化解耦.

    Bridge模式个人在实际代码中见到很少,但其体现的OO思想是很丰富的,可挖掘的东西很多.

    首先,谈刚才讲到的解耦.所谓解耦就是把两个直接依赖的方面,通过增加一层,变成间接依赖,支持动态行为.这一手段必将引入另一个很重要的思想,面向接口编程.通过引入一个接口层,使得原来不可分开的"抽象"和"具体化",变得没有直接依赖.

    其次,解释下为什么要面向接口编程,也就是所谓的具体应该依赖于抽象,抽象不应该依赖于具体.以前自己刚进公司的时候,主管就让我们先熟习下部门主打产品的结构,那个时候头痛的很,一大堆的接口,不知从哪里入手.跟着跟着,就又进了接口,都不知道实际上执行了哪些东东,具体是怎么实现.唯有运行程序,一步步跟进的时候,噢才明白原来调用了哪些哪些方法,但这个时候更容易陷入细枝末节上,缺乏对框架整体的把握.当时的想法就是好复杂啊,为什么定义这么多的接口,可把我害苦了.

    我想这个过程也是很多初学者走过的.现在我来回答你为什么要面向接口编程: 解耦,还是解耦.那为什么我们要解耦.低耦合高内聚为什么如此重要,以至于经常听到别人左一句解耦,右一句解耦的,用来衡量你的设计,衡量产品的质量呢.解耦的目的就是在于隔离(废话,跟没讲似的).隔离的目的在于更好地封装.我以为软件开发就是一个适应需求变化的过程,如何有效适应这个需求不断变化的时代,封装对就是封装.封装就像个缩放镜,可以把某个变化无限缩小,以至于外界丝毫感觉不出你已经变化了.这里说到解耦的最终目的就是有效地封装变化,抵抗需求变化.这句话还隐含的一个意思就是,我们并不要做到什么地方都解耦,唯有容易变化的地方才需要解耦.那些稳定的地方是不需要解耦的.否则容易过度设计,必将自食其果.实际上也不存在完全解耦的软件.上图通用定义一个抽象的接口Implementor,解耦了Abstraction和ConcreteImplementor的关系.然而带来的却是Abstraction依赖于Implementor,这个也就是所谓的耦合.那么为什么这里是可以,原因在于我们认为接口是种契约,是稳定的是不易变化的,具体实现是容易变化的.如果接口都需要改变,那么说明你抽象出来的接口定义有问题,否则无论你用Gof的什么模式都没法很好地解决你变化的问题,夸张的说整个系统是没法有效封装变化,是很脆弱的,很难扩展的.(所幸我们一般都能够抽象出稳定的接口,其稳定的程度在于你的设计经验,对领域相关的知识了解)

    接着再罗嗦一下封装.封装是OOP的3大概念之一,不要以为你真的了解了这3个概念,不要以为你真的融会贯通OOP思想.实际上大部分我们都不清楚,认识的都不够彻底. (m2,这里只是讲讲我的理解而已,大家补充).最开始觉得封装很好理解,把成员私有化,不让外面访问,不就是封装吗.其实远非如此.一个Property封装了field;一个函数封装了实现的细节;一个类封装了职责,等等...这些都是不同细度的封装.真正的意思也许隐藏的更深.(封装用来抵抗变化??)

    接着聊,Bridge体现了单一职责原则.为什么可以使用Bridge模式,为什么能够使用组合的手段,原因在于这个类存在的多个变化点.SRP:就一个类而言,应该仅有一个引起它变化的原因.

    上图来自吕震宇举的非常通俗易懂的蜡笔和毛笔故事.引起蜡笔子类膨胀问题的原因就是蜡笔的职责不够单一,存在大小,和颜色这两个不同方向上的变化.而毛笔的设计就有效地把两个变化点各自封装在不同的对象上.职责单一,而且更好理解实现.

    最后,优先使用组合原则.这个好处重要性不用再说了吧.要是还没有达到这一共识,这篇文章就算白扯了.

    最后的最后,当然这里OCP原则也少不了.(LSP原则呢,个人感觉这个主要在于设计语言的时候用吧,另一个地方就是用于衡量两个类之间可否有继承关系的时候,如椭圆和圆因为违反了LSP原则,所以圆不能继承自椭圆)

    模式比较:

    与Strategy策略模式比较, Strategy主要是在单个支点上变化,主体逻辑保持不变.

    与Decorator装饰者模式比较, 两者都能够有效地解决子类膨胀的问题,但两者在结构上,在应用场合上是完全不同的.Decorator的核心在于互相装饰,体现在某一功能上的扩展(注意"某一功能"这个词,这个体现了其区别另一个模式的地方,以后谈到Decorator的时候再讲). n个装饰类产生的效果,不只是n*n种组合. n*n*n, n*n*n*n都是无限可能的,其组合方式从概念上来讲是无限大的(无限互相装饰的效果). Strategy呢只是用 M*N 替代 M + N,其组合方式是有限的,类的结构决定了他们组合方式的个数,也决定了他们适应的场合.

     

     主要参考资料:

    •李建忠, Webcast设计模式系列

    •阎宏,《Java与模式》,电子工业出版社

    •吕震宇, 设计模式随笔-蜡笔与毛笔的故事

    •idior , Bridge Strategy State的区别

    忘记了最值得推荐的一本书 : <<敏捷软件开发>> Bob大叔

原文地址:https://www.cnblogs.com/anders06/p/812478.html