结构化方法
结构化程序设计方法包含结构化分析(SA)、结构化设计(SD)、结构化程序设计(SP)三个方面,分别对应了软件开发中的分析、设计和编码阶段。
结构化分析是由DeMarco和Yourdon在20世纪70年代所倡导的。结构化分析是一种基于功能分解的分析方法,在分析过程中使用了各种工具,例如数据流图等,这些工具本质上是一个对用户需求的解读,也是面向用户展示的一个“说明书”,目的在于使软件真正符合用户的需求。
结构化设计面向数据流,其最大的着力点在于设计系统各个组成部分之间的内部联系,以满足软件所需要的层次和结构。结构化设计中,软件被自顶向下地不断细分,并谨慎地对待数据流通软件时的每一个步骤。
David Hay曾经说过(1999):"信息工程是1970年代开发的结构化技术的逻辑延伸。结构化编程导致结构化设计,这又导致结构化系统分析。这些技术的特点是使用图表,例如为结构化设计的产生的结构图和为结构化分析而产生的数据流图,这些图表都是为了帮助用户与开发者之间的交流,以及规范化分析、开发过程而产生的。在20世纪80年代,各种工具开始出现,它们自动绘制图表,并跟踪在数据字典中描述的东西。"[1] 例如CAD/CAM这样的CASE工具。
面向对象方法
和结构化设计类似,面向对象技术包括面向对象分析(OOA)、面向对象设计(OOD)和面向对象编程(OOP)三部分。
面向对象方法有几个需要遵循的基本原则:即抽象、封装、继承和多态。
在面向对象建模中,代码和数据被合并成一个单一的不可拆分的单元,也就是一个对象。这样的特性允许对象保持像一个黑盒子,也就是说没有人需要看到里面的具体原理。而为了达到这一点,对任何对象的所有修改是通过作用于对象的消息来完成的,并且实际上所有对象都从消息中获得它们的动作。在面向对象建模中,这种特性被称为封装性,它大大便利了软件部件、包或者库的调用,并且更便于重用。而对象的属性保持私有。[2]
OOP是在20世纪80年代,在结构化程序设计的基础上发展而来的。封装是OOP的基础,其本质在于在数据外构造一个壳、或者说是保护层,以限制外围程序对其的影响。所有对壳内数据的访问都要通过一个间接的层(也就是这个壳)的处理。对于程序来说,编码过程不再需要考虑程序的整个细节,而是对不同的对象(这些对象或许是由别的程序员开发的)发送不同的消息,以使他们产生不同的动作即可,从这个角度来说,程序员进行软件集成的难度很低。例如在Visual Basic语言中,用户界面的窗口、按钮、菜单等均是对象,并且有现成的方法、事件供程序员调用,而程序员不再关心他们的具体执行过程。
两种方法的对比
两种方法的相同点
虽然两种方法的思考方式、方法论不同,但从最终目标上来讲,两种方法是相同的,即它们都是为了设计出符合用户需求的软件。同时,它们都使用了抽象和分解的方法,即对现有的现实问题进行不断地分解,同时也是对现实问题的一种抽象。分解有利于加深对现实问题的理解,并减低解决问题的难度,事实上大部分的工程学都是持有这样的思路的。而抽象,是为了降低软件模块之间的耦合性,让不同部分之间不用过多地互相考虑细节,让不同部分对应分解后的不同子问题,并且利用抽象的性质良好地结合在一起,这便是走出软件设计泥潭,设计出良好软件的不二之路。
在学习编程时,我们被老师们不断地提醒要尽量复用代码。当时我们所使用的方法还比较初级,例如构造函数等。在这两种方法中,重用的思路也被尽量地发扬光大了,良好的部件重用可以大大减小开发和分析的难度。在分解和抽象的基础上,模块重用成了可能。
在细分部件的同时,两种方法都做了各自的努力降低程序的耦合性,提高内聚性,这是公认的良好程序结构的体现。在这种情况下,程序员们,可以更加方便地进行团队工作,这为构造大型软件提供了可能性。
两种方法的不同点
二者不同点的根源在于二者分析问题的视角不同:结构化设计以数据为最关键的实体,着眼于处理数据的整个流程,基于过程地考虑整个数据通过软件时的变化。而面向对象方法则从现实中人的角度考虑问题,将软件功能转变为不同模块的动作和模块间的通信。
由于上述特性,导致了结构化方法和面向对象方法的许多差异。由于结构化设计着眼于数据、信息流,因此数据是与程序分离的一种存在。在整个程序中,数据可能在任何地方被访问,这会导致调试难度的增加,因此也就出现了所谓的一行代码的修改会导致整个程序的变化。最后,结构化方法的这种特性可能就会导致重用性的降低。这种问题的原因在于结构化程序设计方法中,数据是最重要的一环,而数据在程序中是以数据结构的形式体现的,这种数据结构是对现实世界的一种抽象。然而数据如此重要,以至于其很难抽象为某一层,导致其几乎在整个程序中都有可能被使用,这就导致了程序的耦合性的增加。
而在面向对象方法中,数据不再贯穿整个程序,而是成为各个模块的私有属性。这种私有化带来了一些便利:例如数据可以不和算法分离,也更像现实世界中的样子。当然,这样做会增加一个类内部的复杂性,但大大降低了模块之间的耦合性,恰好满足了我们对程序“低耦合,高内聚”的期望。此外,继承性体现了现实世界中的层次、世代关系,多态体现了现实世界的多样性。这种对现实世界的模仿使程序更容易被理解。
两种方法的不同使用环境
面向对象方法并非对结构化方法的完全批判,而是在其基础上吸收其优点,并且引进一些新的概念。结构化方法更适合于那些强调过程,强调对数据的处理的软件。这类软件就像一个流水线,数据进入这个流水线并流出,每一步都是一个结构化的层次。而面向对象方法更适合于那种以功能为特性的软件,面向对象方法以对象为中心,强调一些列对对象的操作,通信。一个很直观的例子就是一个用户界面程序,用户界面中有各种元素,例如输入框、滚动条等。在鼠标的操作下,各类元素有着相应的动作,而这类软件在结构化设计中就会产生低的重用性和很高的耦合性。