开天眼,顿悟软件设计之道

来源:互联网 发布:js清空div里面的内容 编辑:程序博客网 时间:2024/04/27 21:30

本文摘自http://tech.it168.com/j/n/2007-07-10/200707101017099_3.shtml

开天眼,顿悟软件设计之道

 



    【IT168 专稿】夜深人静,四周一片宁静,月光如水银般倾泄,把大地染成一片银白。此时,满天的繁星像无数颗璀璨的宝石,把浩翰的夜空点缀得点点闪烁。与此相影成趣的是亿景公司三楼软开发部却灯火通明。苍穹无言,星月含情。也不知道过了多久,东方的天空开始渐渐发白,不知不觉中已近天明。张力揉搓了一下通红的双眼,然后继续加班修改昨天给项目主管退回来的软件程序。张力是一个软件开发程序员,在昨天的软件项目开发评审会议上,他负责的程序被项目经理西门评点为完全不符合OO设计模式和设计之道。软件设计严重出现四个“腐烂”的征兆,就是过于僵硬、过于脆弱、不可复用性和粘滞性过高。

张力看着窗外发白的天空,想起了项目经理西门对他的评价:一是程序过于僵硬,使软件难以更改,每一个改动都会造成一连串互相依靠的模块的改动,这样的后果是谁也不敢改动,因为他永远也不知道一个改动何时才能完成。二是过于脆弱,会使当软件改动时,系统会在许多地方出错,并且错误经常发生在概念上与改动的地方没有直接联系的模块中。这样的软件无法维护,而且每一次维护都使软件变得更加难以维护。还有就是不可复用性,致使不能复用在其它项目中、或本项目的其它位置中。张力叹了一口气,难道他的软件设计真的象西门经理下班前说的一句话,他还没有开天眼,领悟软件设计之道?

    一.什么是软件设计之道?

    终于挨到了上班的时候,张力赶快洗个脸后走到项目主管西门经理的办公室,向他请教什么是开天眼和悟道。西门看着一整夜没有睡觉而双眼通红的张力说:“什么是道?道是人们对于世界的一些最基本的规律和法则的认识。悟道有五眼六通之说,其中以天眼通为首。大家或多或少都听说过“道”这个词,却不知关键中的关键是什么?简单说就是越是简单的道理越是接近本质。悟者,是能将眼前反观内境,能将身侧远望星空。悟性高的人,是站得更高,看得更远,想得更深,做得更接近本质。悟心就是觉悟之心,我们把透彻一种智慧称为“悟道”。而穿透和超越了事物表象,直接达到事物的本来面目的智慧,可以称作 “顿悟”——就是在刹那间豁然贯通、洞若观火。

    “软件设计也需要用心体会方能悟出软件设计之“道”。软件设计之“道”,也不在于设计有多么的华丽、精巧,而在于其朴实、自然,最终达到“以无招胜有招”,进入一个新的境界”。西门停顿了一下,继续说:“那么,在软件设计过程中是否存在一些基本的原则,我们可以在今天的软件交流会上与各同事再探讨一些在软件设计中最基本的原则”。

    “程序设计的上乘修练方法,可分成两个部份,就是外家功夫和内家功夫。上乘的软件设计之道必须刚柔相济、内外兼修,回归自然,遵守基本法则”。西门在软件设计交流会上总结说:“要想悟出软件设计之道,我们先看看系统的一些“外家”特性,包括可读性、高灵活性、易扩展性、通用性、可移植性,这些特性可概括为“外家白箱特性”。而系统内部也要有一些“内家”属性,如高内聚、低耦合,这些内部属性更侧重内部结构性,概括为“内家黑箱属性”。

    同时,西门还提到为了使一个系统设计具有这些优秀的特性,可使用一些手段和方法。这些方法/手段包括抽象(提高通用性)、封装(增强内聚性)、分离(降低耦合性)等等。当对这些方法/手段进行细化、分类、概括时,就产生了一些设计原则/准则,比如面向接口编程、优先使用对象组合等等。这些准则/原则在一定场景下的经典表现方式,就产生了设计模式。
二.外家白箱之道:可读性与复用性
    软件设计的“外家”白箱之道,包括可读性、高灵活性、易扩展性、通用性、可移植等。这里主要详细介绍两点:一是可读性,二是复用性。

    一个软件的生命周期中,80%的时间和成本花费在维护上。我们可以看到几乎没有任何一个软件,在其整个生命周期中,均由最初的开发人员来维护。无论是从软件的修改,测试还是移植的角度来看,软件的可读性都需要提到一个非常重要的位置上。常用改善软件的可读性方法有编码规范,而不仅仅是详细的注释说明。可读性强的编码规范对于程序员尤为重要,可以让程序员尽快而彻底地理解新的代码。另一个方面,可读性强的设计对测试检查Bug也是非常重要。因此建议在软件设计中必须执行规范,每个软件开发人员必须一致遵守编码规范,提高程序的可读性。

    为了应对软件危机的需要,软件设计原则的最高层次是:复用性、扩展性。很多的软件方案中,开宗明义自己的设计原则是面向对象。那么,当我们把需求影射成为一个一个的对象,就是好的设计吗?事实上,如何划分、设计真正好的对象,是非常难以掌握的。实际上,我们都知道面向对象的基本初衷是代码复用。可复用性是通过复用之前的劳动成果提高开发效率,降低成本。围绕可复用性有很多东西和层次,如代码级别的复用,设计的复用,组件的复用,还有框架的复用等。

    软件的复用除了可以提高软件的生产率,并且恰当的复用可以提高软件的可维护性。在以前,复用主要是代码,函数,结构的复用。而现在复用主要针对类,接口,组件等。但是复用并不一定会保证软件的可维护性。不能因为代码的重复等原因就复用,需要根据具体的情况来分析。要想通过复用来加强系统的可维护性,必须保证复用是支持可维护性的复用。

    下面的一些最基本的确设计原则可以用来指导实践。
    开-闭原则(OCP):开闭原则是面向对象可复用的基石。它主要指:一个软件实体对扩展开放,对修改关闭。在设计一个模块的时候,应当是这个模块在不被修改的前提下被扩展。满足这个原则的系统在一个较高层次上实现了复用,也是易于维护的。
    那如何才能满足开闭原则呢?抽象化是关键,要区分开抽象层和实现层。在一个软件系统中,抽象层应该是相对稳定的,而实现层是可以改变和扩展的。我们可以把许多事物和问题抽象起来,并且抽象它们不同的层次和角度。开闭原则也是对可变性的封装原则,找到系统的可变因素,并将其封装起来。把一种可变性封装为一个对象,那么这种可变性的不同表象就是这个类的具体子类。

    里氏代换原则(LSP):里氏代换原则是继承复用的基石:在任何父类出现的地方都可以用它的子类来替代。实际上,设计类的阶层体系结构时,这是一条很重要的原则。另一个需要着重提到的是依赖倒转原则(DIP):就是说要依赖于抽象,不要依赖于具体的实现。在传统的过程性系统中,高层的模块依赖于低层次的模块,抽象层次依赖于具体层次。这样导致了底层的任何改变都会影响到上层。这样的软件系统没有可维护性而言。抽象层次应该不依赖于具体的实现细节,这样才能保证系统的可复用性和可维护性,这也就是所谓的倒转。

     在实际中如何应用这一原则呢?要针对接口编程,而不针对实现编程。那么当实现变化时,不会影响到其他的地方。在java中应当使用接口和抽象类来进行变量的类型声明,参数的类型声明,方法的返回值类型等等。以抽象的方式进行耦合是依赖倒转原则的关键。依照依赖倒转原则,在系统中会出现大量的类,如抽象类和接口,因为它假定所有的具类都是有可能变化的。
三.内家黑箱之道:低耦合、高聚合

    如果将设计好的对象之间用有向箭头连在一起,很多时候会变成了一张网,如果将对象的方法之间用有向箭头连在一起,则看起来像信手涂鸦。对于设计人员,能够将其中的关系一一说明清楚也是一个困难的事情,而对于的开发人员,则变成了黑洞。当用户需求发生变化时,这样的设计会成为噩梦,当然这是比较极端的情况。但是也能说明,在设计各个层面减少耦合是关键。

    一般来说,大部份的软件内部都是包含多个模块的,各个模块之间或多或少的存在一些耦合。这些功能的耦合,最理想的一种状态,就是可配置,可装卸。任何一个模块的去除,不至于影响到其他功能。并且,更多的功能是采用配置的。就是说,各个模块,就像搭积木一样,可以把其中的一块替换掉,或者拿掉,但不可以影响其他的功能。可配置,可装卸的软件,必将是未来软件更为理想的开发模式。这对于系统的维护,以及需求的变更适应性都是非常好的。

    因此“内家黑箱”设计之道是:低耦合、高聚合。各种软件设计的原则,如依赖倒置原则、单一职则原则、面向接口等,以及各种设计模式,其根本的目的其实只是为了降低耦合。因为只有低耦合才能更好的适应变化,更好的复用和扩展。

    一般来说,我们常用的实现方法是:运用设计模式封装变化、降低耦合。设计模式是用来“封装变化、降低耦合”的工具。它是面向对象设计的产物,其本质就是充分运用面向对象的三个特性,即:封装、继承和多态,进行灵活的组合运用。

    当然,耦合无论如何也是不可避免的。当我们实现接口、继承父类的时候,就会不可避免的产生耦合。但耦合是有不同粒度的,我们必须非常清楚的是解耦需要到什么粒度为止。一般来说应以模块的复用粒度为准,尽量解除复用模块或对象之间的耦合。而复用模块之内的耦合,应属于聚合的范畴,所以不要盲目的去解耦,否则就陷入了误区。

    在这里,我们再回达头来看看怎样才能解耦。一般有以下两个思路:(1)将具体的东西抽象处理。(2)将分散的东西集中处理。降低耦合,也就是解耦是关键。当我们实现了低耦合,高内聚,也同时达到了软件设计的另一个目标高扩展,高复用。
 
原创粉丝点击