一、结构化编程和结构化设计
1.结构化编程
最早的高级语言编程保留了汇编语言中的跳转模式,使用goto语句,可以在整个程序的任意位置进行跳转。1966年5月,科拉多·伯姆(Corrado Böhm)及朱塞佩·贾可皮尼(Giuseppe Jacopini)伯姆在《Communications of the ACM》期刊发表论文,说明任何一个有goto指令的程式,可以改为完全不使用goto指令的程式[1]。1968年荷兰教授E.W.Dijkstra提出“GOTO语句是有害的”的观点,引发了广泛的讨论。由于goto语句可取代,该争论逐渐转向思考如何使编写程序更高效、更清晰。[2]1974年D.E.Knuth提出“带有goto的结构化程序设计”,肯定了提高程序清晰性的结构化编程思路,但保留可用的goto语句。
在一个函数内,代码执行的方式有顺序执行、选择执行与循环执行,后两种分别对应选择型语句(if、switch等)与循环语句(for、while等);程序又会按功能分为不同的函数,函数需要有正确的入口和出口。任何程序执行的过程不能随意打断。这种结构的层层嵌套可能会导致程序执行效率下降,但程序可读性大大提高。
为了进一步提升可读性,将程序保存为字符串时还可以采用一些额外的缩进方式。一般来说:
statement1;
{statement2;
statement3;}
型语句的可读性不如:
statement1;
{
statement2;
statement3;
}
一般不提倡使用goto,但某些情况下goto会使结构更加简单。以LL(1)的编译程序为例:
int factor(){}
int term(){}
int expression(){}
int statement(){}
当程序正常执行时,应当按照statementàexpressionàtermàfactor……的顺序进行,其中函数expression、term、factor都可能会被递归若干次。若输入的程序有误,应当停止对此语句(statement)的编译,并尝试错误局部化(例如,跳转到一个分号之后)。此时,使用goto直接跳出函数factor、term或expression比使用错误标记的层层return更清晰。
对goto语句,一般而言,向前的goto语句更不容易产生麻烦。尽量不使用可能造成循环的goto语句。
2.结构化程序设计
将结构化编程中程序设计部分单独提取,即为结构化程序设计。设计应当优先于代码,尽量在设计完成后再开始编码。常用方法有N-S图、流程图等。
(1) 主张使用顺序、选择、循环三种基本结构来嵌套连结成具有复杂层次的“结构化程序”,严格控制GOTO语句的使用。用这样的方法编出的程序在结构上具有以下效果:
a. 以控制结构为单位,只有一个入口,一个出口,所以能独立地理解这一部分。
b. 能够以控制结构为单位,从上到下顺序地阅读程序文本。
c.由于程序的静态描述与执行时的控制流程容易对应,所以能够方便正确地理解程序的动作。
(2)“自顶而下,逐步求精”的设计思想,其出发点是从问题的总体目标开始,抽象低层的细节,先专心构造高层的结构,然后再一层一层地分解和细化。这使设计者能把握主题,高屋建瓴,避免一开始就陷入复杂的细节中,使复杂的设计过程变得简单明了,过程的结果也容易做到正确可靠。
(3)“独立功能,单出、入口”的模块结构,减少模块的相互联系使模块可作为插件或积木使用,降低程序的复杂性,提高可靠性。程序编写时,所有模块的功能通过相应的子程序(函数或过程)的代码来实现。程序的主体是子程序层次库,它与功能模块的抽象层次相对应,编码原则使得程序流程简洁、清晰,增强可读性。
(4) 主程序员组。[3]
对一个已经进行过结构化程序设计的项目,编码的任务只是将设计好的程序流程转化为对应的计算机语言,程序整体结构易把握,更容易进行查错、功能调整;模块之间基本独立,不会受到牵连。
二、面向对象方法
面向对象是一种与结构化方法不同的设计思路。面向对象设计方法首先关注对象的性质,而不是需要的功能。面向对象的设计中,描述对象的性质抽象形成类,类具有自己的特性,也包含自身所能进行的操作;程序运行时,对象继承类的行为相互传递消息。
事实上,面向对象方法,同结构化方法一样,都是为了设计出清晰易读的程序、编写代码更加高效,但思路不同。
面向对象方法通常包含以下概念:
对象:即设计中需要描述的事物。
状态:用来描述对象某一方面的性质。通常一个对象可以有多个状态,可以体现不同方面的性质。在程序中,状态用数据表示。
行为:用来改变对象状态的操作。在程序中,对象的行为用函数表示。
类:具有相同状态类型和行为的对象的集合。通常也可以说“类的状态”和“类的行为”。一般情况下,类的行为函数并不定义在程序内,只定义在类内,只有该类的对象才能够调用(即:方法只能面向对象)通常情况下,一个单独的类不能够完整描述对象的全部特性,或者说不同对象的状态不完全相同。因此类之间存在继承关系,子类包含父类的全部方法。
消息:对象之间进行通信的方式。
三、结构化方法与面向对象方法的对比
首先,需要肯定的是,结构化方法与面向对象方法都是为了对程序进行更好的设计、实现而采用的手段,目标都是更好地完成程序设计,现在也达到了目标。两者的程序可读性与结构性都很强。但结构化编程采用的还是最初的过程化思路,而面向对象采用了以对象为主的思路,因此程序差异很大。
1.设计思路:结构化方法采用自顶向下的设计,逐步具体形成结构;面向对象方法从对象开始,自底向上完成程序的构建
2.扩展性:结构化方法对每个过程进行细化(以函数的形式),面向对象方法对每个类进行完善,两者方法有所区别。一般来说,面向对象方法会具有更好的扩展性。
3.控制方式:结构化方法采用函数参量与返回值的方式,进出口唯一;面向对象方法采用程序间通信的方式。
4.可修改性/维护性/重用性:结构化方法对外的是程序接口,当程序需求发生变化时,可能需要大量修改;面向对象方法对外的接口是类函数接口,程序需求变化时通常不会对类造成影响。但是,这并不意味着结构化方法的可修改性一定比面向对象方法要差。由于类的不可见性,从类的外部进行维护通常难度很大;当类需求发生变化时,对类的修改难度要超过对结构化程序的程序修改。
5.代码可读性:相对于早期的高级语言程序,两者在可读性上都有很大提升。面向对象方法的类可能会包含一些当前程序不需要的属性与方法,从而使可读性不如结构化程序,并造成代码冗余。
参考资料:
[1]百度百科:结构化编程
[2] 汤铭端:软件工程与软件可靠性 第二讲 结构化方法
[3]百度百科:结构化程序设计