开闭原则和设计模式

    在《敏捷软件开发--原则、模式与实践》书中给出了多个OO设计原则,例如单一职责、开闭原则、依赖倒置原则等。在这些原则中,绝大多数都很容易理解,最难理解的恐怕算开闭原则(对扩展开放,对修改关闭),主要原因是它太抽象,是一个比较本质的设计原则,超出了一个人的理解范围,如果能有一个实际的具体例子来说明就容易理解了。

   其实在设计模式中,就有这样的一些模式很好的直接体现了开闭原则。

   先暂时岔开一下说说设计模式,设计模式的流行应该是归功和发端于四人帮的《设计模式--可复用面向对象软件的基础》一书的出版,自此设计模式才开始为IT大众所知晓。

   很多设计模式的的本质是封装需求的变化,而需求唯一不变的就是变化,变化是客观的,通常是很难避免的,所以设计模式是应对需求变化的一种重要技术手段,以不变应万变才是上策。

   怎么应对变化?其实在日常工作生活中就可以找到应对变化的手段。对各种气体(如气体喷雾剂)和液体(如水),由于它们没有固定的形状,也就是容易变化,所以我们需要用容器(瓶瓶罐罐)将它们封装起来,隔离屏蔽起来,否则任由它们蔓延,肯定会把周围的环境污染得一滩糊涂,难以收拾。为了防范洪水猛兽,人们修建各种设施将它们关起来,局限隔离起来。

  类推到软件中也是这样,软件中的变化类似洪水猛兽,也需要进行封装隔离,如果让变化任意到处蔓延,污染其他的代码,那么受污染的代码就和容易变化的代码产生了较强的耦合,耦合太强太多,就变成意大利面条了,导致有新的变化时,代码难以维护,一旦后面要拥抱变化,那就悲剧了:开发人员要到处查找受污染的代码进行修改,少修改一处就出bug。

   因此我们应追求低耦合高内聚,减少依赖。对容易变化的代码,就要日常生活中那样,将变化封装隔离起来,对它进行管束&限制,隔离起来,不让变化到处扩散,减少或尽量屏蔽它和其余部分之间的耦合。

  而设计模式的主要目的就是封装变化,所以掌握设计模式是开发人员的重要技能之一。

  设计模式学起来其实不太难,根据我的经验,一个对设计模式一无所知的的开发人员,把四人帮的设计模式一书认真读两遍基本可掌握。但要注意学习方法,要带着问题去读,对书中的每个设计模式,在读完它要解决的问题时,先停下来,问问自己,碰到这样的问题如何优雅的解决。思考完再继续读下去,再反思下自己为何没想到答案,再对照书中的类图和序列图、代码仔细揣摩体会下该设计模式的精妙。这样才有可能在自己的思想中产生较为深刻的理解,否则就是浮光掠影,没有效果。最后一定要在自己的开发工作中找合适的机会实践一下,不一定都用到,首先是要找到变化点,深入到变化点中去,再对照具体的问题场景,选择对应的模式。我的实践经验是在较多场景中都会用到模板方法(框架中用的更多)、代理模式、策略模式、命令模式、facade、工厂方法等。只有在潜意识中留下设计模式的烙印才算真正掌握了设计模式的精髓,以后一碰到问题,从直觉上就能较快知道应该选用哪种设计模式。

  由于变化的多样性,也就是变化有不同类型和不同维度,所有就要有多个不同的设计模式来应对相应的变化。另外除了四人帮书中所讲的3种类型的模式(创建型、结构性、行为型),其实还有很多其他类型的设计模式,在分布式系统领域、资源管理领域、应用集成领域就有很多其他类型的模式。

   回到正题,四人帮书中的哪个设计模式直接体现了开闭原则?说的是直接,当然很多模式都间接体现了该原则。

  开闭原则(扩展开放,对修改关闭)的完整意思是需求变化时要能通过增加代码来实现,这样就扩展了新的功能(对扩展开放),但不要修改先前的模块代码或底层框架核心层代码(对修改关闭),多优雅。显然如果修改核心层代码,很可能会引入风险,还有一种可能是核心层如果是二进制库(第二方或三方dll、jar包),你还无法修改,没源码啊,除非进行反向工程,反编译。这样如果增加功能需要修改核心层,就很难办到了。而遵照开闭原则的设计就不必担忧此问题,因为只需在使用核心层的外围模块(有源码控制权)中增加新代码,不需涉及到核心层。

  答案是Visitor模式,该模式的类图就不画了。对照该模式的类图,可以发现有两个大的类层次,一个是Visitor层次(Visitor基类&接口和它的众多子类&实现类),另一个是数据元素层次(Element/Node和它的众多子类)。

   采用该模式,如果要增加新的算法操作,只需要增加一个Visitor的实现类,先前的核心代码(数据元素层次)不用修改,这不正直接体现了开闭原则!

    正如四人帮的书中指出,该模式不是万能的,任何模式都有适用范围。如果变化点在数据元素层次(Element/Node层次)该模式就不太管用了。

   模板方法、builder模式等也比较好地体现了开闭原则。很多框架也使用这些模式来提供扩展点,通过回调这些扩展点中的方法,以便拥抱具体应用中的变化。

猜你喜欢

转载自wanshi.iteye.com/blog/1916448