程序设计教程:用C++语言编程(第4版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.2.2 程序设计步骤

有人认为程序设计是一门艺术,而艺术在很大程度上依赖于人的灵感和天赋,它往往没有具体的规则和步骤可循。对于一些小型程序的设计,上述说法有一些道理,灵感和天赋往往会在程序的一些局部设计上发挥作用。但是,对于大型、复杂的程序设计问题,灵感和天赋是不能很好地解决问题的,几十年的程序设计实践已表明了这一点。从总体上讲,程序设计是一门科学,而科学的东西是有规律和步骤可循的。

一个软件从无到有,一直到最后的消亡(报废),通常要经历一个过程,这个过程称为软件生命周期(software life cycle)。软件生命周期分为若干阶段:软件需求分析、软件系统设计、编程实现、测试以及运行与维护,早期的软件开发工作主要集中在编程实现阶段。随着计算机应用领域的不断扩大和应用层次的不断加深,软件的规模不断扩大、软件的复杂度不断提高,早期的软件开发模式难以驾驭软件开发过程,程序的正确性难以保证,软件生产率急剧下降,出现了“软件危机”。为了解决软件危机,软件工程(software engineering)应运而生,其主要思想是采用工程方法来开发软件,强调对软件开发过程的管理并加强各个阶段的文档制作。

从软件工程的角度来讲,程序设计是指软件生命周期中编程实现阶段的工作。而实际上,由于程序设计概念的出现早于软件工程,因此,通常所说的程序设计也包含软件生命周期中其他阶段的一些工作,只是更多地考虑实现技术。因此,不能把程序设计仅仅理解成用某种语言来实现设计好的软件,还必须考虑需求分析、系统设计、测试以及维护等问题。

一般来说,程序设计要遵循以下步骤。

1.需求分析

用计算机程序来解决实际问题,首先需要明确要解决的问题是什么,即程序要做什么(what to do)。如果对待解决的问题都没弄清楚或理解错了,就试图去解决它,会有什么结果是可想而知的。所以,首先弄清楚要解决的问题并给出问题的明确定义是解决问题的关键,这一步工作称为需求分析(requirement analysis)。

2.系统设计

明确问题之后,接下来就要考虑如何解决它,即程序如何做(how to do)。在解决如何做之前,首先要以计算机解决问题的方式设计出一个解决方案,这一步工作称为系统设计(system design)。系统设计可分为概要设计和详细设计。概要设计是给出程序的总体结构,即程序由哪几部分构成以及它们之间的关系;详细设计是针对程序的每个部分给出具体的解决方案。

不同的程序设计范式决定了不同的设计方案和设计结果。对于过程式程序设计范式,概要设计采用的是功能分解和复合策略,它要指出系统包含哪些子功能以及它们之间的关系;对于面向对象程序设计范式,概要设计采用的是数据抽象策略,它要指出系统包含哪些对象和类以及它们之间的关系。在进行详细设计时,则给出数据结构和算法的描述。至于如何组织数据结构和算法的描述,不同的范式是有区别的。在过程式程序设计中,数据结构和算法描述是分开的,而在面向对象程序设计中,则把两者结合成对象和类来考虑。

在进行系统设计时,往往采用某种抽象的不依赖于具体程序设计语言的形式来描述设计的结果,如采用功能模块结构图、流程图、类图以及伪代码等,这样做的目的是避免一开始就陷入某种程序设计语言的实现细节中,因为过多地涉及实现细节,不利于从较高抽象层次考虑问题的本质,导致难以把握和理解设计过程,失去设计方向。

3.系统实现

用流程图、伪代码等描述的设计方案是不能直接在计算机上执行的,必须要用某种实际的能被计算机理解的程序语言把它们表示出来,才能在计算机上执行,这一步工作称为系统实现(system implementation),也叫编程(coding)[3],所采用的语言称为编程语言或程序设计语言。

在进行系统实现时,首先面临的是编程语言的选择问题。现在的编程语言有很多(多达上百种),采用哪一种语言来编程呢?从理论上讲,虽然各种编程语言之间存在着或多或少的差别,但它们大多数都是基于冯·诺依曼体系结构的,在表达能力上是等价的,对同一个问题,往往用任何一种编程语言都能实现。然而,在实际应用中,用哪一种语言来编程往往受到很多因素的制约,如程序的设计方案、程序的应用场合以及程序的运行平台(计算机硬件+操作系统)等都会影响编程语言的选择。另外,一些非技术因素也会影响编程语言的选择。例如,某软件公司现有的编程、维护人员只熟悉某种语言,如果选择其他语言,则将意味着需要对已有人员进行培训或招聘新的编程人员,而这些都需要时间和资金投入。

除了编程语言的选择之外,系统实现中还要考虑编程风格问题。在采用某种编程语言编写程序的时候,不同的人会写出不同风格的程序,而风格有好与不好之分,它会影响程序的正确性和易维护性。编程风格取决于编程人员对程序设计的基本思想、概念、技术以及编程语言精髓的掌握程度,良好的编程风格是可以通过学习和训练来获得的。

4.测试与调试

用某种编程语言写出的程序可能包含错误。程序错误通常有三种:语法错误、逻辑(或语义)错误以及运行异常错误。语法错误是指程序没有按照语言的语法规则来编写,逻辑错误是指程序没有完成预期的功能,而运行异常错误是指对程序运行环境的非正常情况考虑不足而导致的程序异常终止。

程序的语法错误可由语言的翻译程序来发现,而程序的逻辑错误和运行异常错误则一般通过测试(testing)来发现。测试方法可分为静态测试与动态测试。静态测试是指不运行程序,而是通过对程序的静态分析找出逻辑错误和异常错误。动态测试是指利用一些测试数据,通过运行程序来观察程序的运行结果与预期的结果是否相符。值得注意的是,不管采用何种测试手段,都只能发现程序中的错误,而不能证明程序正确,即测试的目的就是要尽可能多地发现程序中的错误。测试工作不一定要等到程序全部编写完成才开始,可以采取编写一部分、测试一部分的方式来进行,最后再对整个程序进行整体测试,即先进行单元测试,再进行集成测试。

如果通过测试发现程序有错误,那么就需要找到程序中出现错误的位置和原因,即错误定位。给错误定位的过程称为调试(debugging),它一般需要运行程序,通过观察程序的阶段性运行结果来找出错误的位置和原因。

5.运行与维护

程序通过测试后就可交付使用了。由于所有的测试手段只能发现程序中的错误,而不能证明程序没有错误,因此,在程序的使用过程中还会不断发现程序中的错误。在使用过程中发现并改正程序错误的过程称为程序的维护(maintenance)。程序维护可分成三类:正确性维护、完善性维护以及适应性维护。正确性维护是指改正程序中的错误;完善性维护是指根据用户的要求使程序功能更加完善;适应性维护是指把程序移植到(拿到)不同的计算平台或环境中,使之能够运行。

值得一提的是,程序维护所花费的人力和物力往往是巨大的,因为只要程序在使用就需要对它进行维护。因此,程序的易维护性就显得非常重要了,而程序的易维护性取决于所采用的程序设计技术的优劣,其中包括编程风格。