软件工程中文讲义4.docx
- 文档编号:27126524
- 上传时间:2023-06-27
- 格式:DOCX
- 页数:43
- 大小:53.06KB
软件工程中文讲义4.docx
《软件工程中文讲义4.docx》由会员分享,可在线阅读,更多相关《软件工程中文讲义4.docx(43页珍藏版)》请在冰豆网上搜索。
软件工程中文讲义4
软件工程中文讲义4
第四章程序编码
一、复习要求
1.了解什么是结构化程序设计,以及结构化程序设计的原则。
2.了解程序设计风格4个方面的要求。
3.了解提高程序效率的方法。
4.了解程序设计语言的分类和特点。
5.掌握度量程序复杂性的McCabe方法和Halstead方法。
二、内容提要
1.结构化程序设计
结构化程序设计技术是60年代中期提出来的,它主要包括两个方面:
在编写程序时,强调使用几种基本控制结构,通过组合嵌套,形成程序的控制结构。
尽可能避免使用会使程序质量受到影响的GOTO语句。
在程序设计过程中,尽量采用自顶向下和逐步细化的原则,由粗到细,一步步展开。
(1)结构化程序设计的原则
使用语言中的顺序、选择、重复等有限的基本控制结构表示程序逻辑。
选用的控制结构只准许有一个入口和一个出口。
程序语句组成容易识别的块,每块只有一个入口和一个出口。
复杂结构应该用基本控制结构进行组合嵌套来实现。
语言中没有的控制结构,可用一段等价的程序段模拟,但要求该程序段在整个系统中应前后一致。
严格控制GOTO语句,仅在用一个非结构化的程序设计语言去实现一个结构化的构造,或者在某种可以改善而不是损害程序可读性的情况下才可以使用GOTO语句。
大量采用GOTO语句实现控制路径,会使程序路径变得复杂而且混乱,因此要控制GOTO语句的使用。
但有时完全不用GOTO语句进行程序编码,比用GOTO语句编出的程序可读性差。
例如,在查找结束时,文件访问结束时,出现错误情况要从循环中转出时,使用布尔变量和条件结构来实现就不如用GOTO语句来得简洁易懂。
对于常用的高级程序设计语言,一般都具备前述的几种基本控制结构。
即使不具备等同的结构,也可以采用仿真来实现。
下面以FORTRAN77为例进行说明,参看图4.1。
基本控制结构
用FORTRAN77模拟基本控制结构
判断语句
if(p)S1;
elseS2;
IF(p)THEN
S1
ELSE
S2
ENDIF
先判断型循环语句
while(p)
S;
100CONTINUE
IF(p)THEN
S
GOTO100
ENDIF
后判断型循环语句
doS;while(p);
100CONTINUE
S
IF(p)GOTO100
图4.1用FORTRAN77语句实现基本控制结构
(2)程序设计自顶向下,逐步求精
在详细设计和编码阶段,应当采取自顶向下,逐步求精的方法,把一个模块的功能逐步分解,细化为一系列具体的步骤,进而翻译成一系列用某种程序设计语言写成的程序。
例如,要求用筛选法求100以内的素数。
所谓筛选法,就是从2到100中去掉2,3,…,9,10的倍数,剩下的就是100以内的素数。
为了解决这个问题,可先按程序功能写出一个框架。
main(){
建立2到100的数组A[],其中A[i]=i;-------------------------1
建立2到10的素数表B[],其中存放2到10以内的素数;------------2
若A[i]=i是B[]中任一数的倍数,则剔除A[i];--------------------3
输出A[]中所有没有被剔除的数;-------------------------------4
}
上述框架中每一个加工语句都可进一步细化成一个循环语句。
main(){
/*建立2到100的数组A[],其中A[i]=i*/------------------------1
for(i=2;i<=100;i++)A[i]=i;
/*建立2到10的素数表B[],其中存放2到10以内的素数*/-----------2
B[1]=2;B[2]=3;B[3]=5;B[4]=7;
/*若A[i]=i是B[]中任一数的倍数,则剔除A[i]*/--------------------3
for(j=1;j<=4;j++)
检查A[]所有的数能否被B[j]整除并将能被整除的数从A[]中剔除;--------3.1
/*输出A[]中所有没有被剔除的数*/-------------------------------4
for(i=2;i<=100;i++)
若A[i]没有被剔除,则输出之;-----------------------------------4.1
}
继续对3.1和4.1细化下去,直到最后每一个语句都能直接用程序设计语言来表示为止。
main(){
for(i=2;i<=100;i++)A[i]=i;
B[1]=2;B[2]=3;B[3]=5;B[4]=7;
/*若A[i]=i是B[]中任一数的倍数,则剔除A[i]*/
for(j=1;j<=4;j++)
/*检查A[]所有的数能否被B[j]整除并将能被整除的数从A[]中剔除*/
for(i=2;i<=100;i++)
if(A[i]/B[j]*B[j]==A[i])A[i]=0;
/*输出A[]中所有没有被剔除的数*/
for(i=2;i<=100;i++)
/*若A[i]没有被剔除,则输出之*/
if(A[i]!
=0)
printf(“A[%d]=%d\n”,i,A[i]);
}
自顶向下,逐步求精方法的优点:
①自顶向下,逐步求精方法符合人们解决复杂问题的普遍规律。
可提高软件开发的成功率和生产率;
②用先全局后局部,先整体后细节,先抽象后具体的逐步求精的过程开发出来的程序具有清晰的层次结构,因此程序容易阅读和理解;
③程序自顶向下,逐步细化,分解成一个树形结构(如图4.2所示)。
在同一层的结点上做的细化工作相互独立。
在任何一步发生错误,一般只影响它下层的结点,同一层其它结点不受影响。
在以后的测试中,也可以先独立地一个结点一个结点地做,最后再集成。
④程序清晰和模块化,使得在修改和重新设计一个软件时,可复用的代码量最大;
⑤每一步工作仅在上层结点的基础上做不多的设计扩展,便于检查;
⑥有利于设计的分工和组织工作。
(3)数据结构的合理化
H.Mills指出,结构化程序设计主要是想从程序的控制结构入手,消除不适应的、容易引起混乱的GOTO语句。
这只是问题的一个方面,而问题的另一方面,过去没有注意到的是数据结构的合理化问题,即数据结构访问的规范化,标准化问题。
假如数据结构中常使用数组、指针等数据类型,则对它们必须采取随机访问,这样势必产生访问上的混乱。
例如,要访问数组元素A[i][j],必须先对下标i,j访问,造成访问忽前忽后,这与GOTO语句造成的混乱类似,同样是有害的。
H.Mills指出,解决这一问题的办法是用栈和队列去代替数组和指针。
栈与队列分别是按后进先出(LIFO)和先进先出(FIFO)的原则进行存取的。
在程序中用栈和队列代替数组和指针,用合理的规范的顺序存取代替随机存取,将克服随机存取带来的麻烦。
而且有人做了证明,所有使用数组和指针的程序,都可以使用栈和队列的程序等价替换。
2.程序设计风格
在软件生存期中,人们经常要阅读程序。
特别是在软件测试阶段和维护阶段,编写程序的人与参与测试、维护的人都要阅读程序。
因此,阅读程序是软件开发和维护过程中的一个重要组成部分,而且读程序的时间比写程序的时间还要多。
70年代初,有人提出在编写程序时,应使程序具有良好的风格。
程序设计风格包括4个方面:
源程序文档化,数据说明,语句结构和输入/输出方法,力图从编码原则的角度提高程序的可读性,改善程序质量。
(1)源程序文档化
在编写程序时,需注意数据说明的风格。
为了使程序中数据说明更易于理解和维护,必须注意以下几点。
数据说明的次序应当规范化,使数据属性容易查找。
当多个变量名用一个语句说明时,应当对这些变量按字母的顺序排列。
如果设计了一个复杂的数据结构,应当使用注释来说明在程序实现时这个数据结构的固有特点。
(3)语句结构
在设计阶段确定了软件的逻辑流结构,但构造单个语句则是编码阶段的任务。
语句构造力求简单,直接,不能为了片面追求效率而使语句复杂化。
在一行内只写一条语句,并且采取适当的移行格式,使程序的逻辑和功能变得更加明确。
程序编写首先应当考虑清晰性,不要刻意追求技巧性,使程序编写得过于紧凑。
程序编写得要简单,写清楚,直截了当地说明程序员的用意。
除非对效率有特殊的要求,程序编写要做到清晰第一,效率第二。
不要为了追求效率而丧失了清晰性。
事实上,程序效率的提高主要应通过选择高效的算法来实现。
首先要保证程序正确,然后才要求提高速度。
反过来说,在使程序高速运行时,首先要保证它是正确的。
让编译程序做简单的优化。
尽可能使用库函数。
避免使用临时变量而使可读性下降。
尽量用公共过程或子程序去代替重复的功能代码段。
用调用公共函数去代替重复使用的表达式。
使用括号来清晰地表达算术表达式和逻辑表达式的运算顺序。
避免不必要的转移。
同时如果能保持程序的可读性,则不必用GOTO语句。
尽量只采用三种基本的控制结构来编写程序。
用逻辑表达式代替分支嵌套。
避免使用空的ELSE语句和IF…THENIF…的语句。
避免使用ELSEGOTO和ELSERETURN结构。
使与判定相联系的动作尽可能地紧跟着判定。
避免采用过于复杂的条件测试。
尽量减少使用“否定”条件的条件语句。
不要让读者绕弯子想。
避免过多的循环嵌套和条件嵌套;
不要使GOTO语句相互交叉。
避免循环的多个出口。
使用数组,以避免重复的控制序列。
尽可能用通俗易懂的伪码来描述程序的流程,然后再翻译成必须使用的语言。
数据结构要有利于程序的简化。
要模块化,使模块功能尽可能单一化,模块间的耦合能够清晰可见。
利用信息隐蔽,确保每一个模块的独立性。
从数据出发去构造程序。
不要修补不好的程序,要重新编写。
也不要一味地追求代码的复用,要重新组织。
对太大的程序,要分块编写、测试,然后再集成。
对递归定义的数据结构尽量使用递归过程。
注意计算机浮点数运算的特点,例如,浮点数运算10.0*0.1通常不等于1.0。
不要单独进行浮点数的比较。
用它们做比较,其结果常常发生异常情况。
避免不恰当地追求程序效率,在改进效率前,要做出有关效率的定量估计。
在程序中应有出错处理功能,一旦出现故障时不要让机器进行干预,导致停工。
此外,对于程序中的变量,标号,注释等,还需要给予一些注意。
例如,
变量名中尽量不用数字。
显式说明所有的变量。
确保所有变量在使用前都被初始化。
确保注释与代码完全一致。
不仅对代码做注释,而且对每条注释都加以编号。
不注释不好的代码,要重新编写。
程序格式的安排应有助于读者理解程序。
注释不要过于繁琐。
遵循国家标准。
经常反躬自省:
“如果我不是编码的人,我能看懂它吗?
”考虑它的可理解性达到什么程度。
(4)输入和输出(I/O)
输入和输出信息是与用户的使用直接相关的。
输入和输出的方式和格式应当尽可能方便用户的使用。
因此,在软件需求分析阶段和设计阶段,就应基本确定输入和输出的风格。
系统能否被用户接受,有时就取决于输入和输出的风格。
不论是批处理的输入/输出方式,还是交互式的输入/输出方式,在设计和程序编码时都应考虑下列原则:
对所有的输入数据都进行检验,从而识别错误的输入,以保证每个数据的有效性;
检查输入项的各种重要组合的合理性,必要时报告输入状态信息;
使得输入的步骤和操作尽可能简单,并保持简单的输入格式;
输入数据时,应允许使用自由格式输入;
应允许缺省值;
输入一批数据时,最好使用输入结束标志,而不要由用户指定输入数据数目;
在以交互式输入/输出方式进行输入时,要在屏幕上使用提示符明确提示交互输入的请求,指明可使用选择项的种类和取值范围。
同时,在数据输入的过程中和输入结束时,也要在屏幕上给出状态信息;
当程序设计语言对输入/输出格式有严格要求时,应保持输入格式与输入语句的要求的一致性;
给所有的输出加注解,并设计输出报表格式。
输入/输出风格还受到许多其它因素的影响。
如输入/输出设备(例如终端的类型,图形设备,数字化转换设备等)、用户的熟练程度、以及通信环境等。
Wasserman为“用户软件工程及交互系统的设计”提供了一组指导性原则,可供软件设计和编程参考。
把计算机系统的内部特性隐蔽起来不让用户看到;
有完备的输入出错检查和出错恢复措施,在程序执行过程中尽量排除由于用户的原因而造成程序出错的可能性;
如果用户的请求有了结果,应随时通知用户;
充分利用联机帮助手段,对于不熟练的用户,提供对话式服务,对于熟练的用户,提供较高级的系统服务,改善输入/输出的能力;
使输入格式和操作要求与用户的技术水平相适应。
对于不熟练的用户,充分利用菜单系统逐步引导用户操作;对于熟练的用户,允许绕过菜单,直接使用命令方式进行操作;
按照输出设备的速度设计信息输出过程;
区别不同类型的用户,分别进行设计和编码;
保持始终如一的响应时间;
在出现错误时应尽量减少用户的额外工作。
在交互式系统中,这些要求应成为软件需求的一部分,并通过设计和编码,在用户和系统之间建立良好的通信接口。
3.程序效率
(1)讨论效率的准则
程序的效率是指程序的执行速度及程序所需占用的内存的存储空间。
讨论程序效率的几条准则为:
效率是一个性能要求,应当在需求分析阶段给出。
软件效率以需求为准,不应以人力所及为准。
好的设计可以提高效率。
程序的效率与程序的简单性相关。
一般说来,任何对效率无重要改善,且对程序的简单性、可读性和正确性不利的程序设计方法都是不可取的。
(2)算法对效率的影响
源程序的效率与详细设计阶段确定的算法的效率直接有关。
在详细设计翻译转换成源程序代码后,算法效率反映为程序的执行速度和存储容量的要求。
转换过程中的指导原则是:
在编程序前,尽可能化简有关的算术表达式和逻辑表达式;
仔细检查算法中的嵌套的循环,尽可能将某些语句或表达式移到循环外面;
尽量避免使用多维数组;
尽量避免使用指针和复杂的表;
采用“快速”的算术运算;
不要混淆数据类型,避免在表达式中出现类型混杂;
尽量采用整数算术表达式和布尔表达式;
选用等效的高效率算法;
许多编译程序具有“优化”功能,可以自动生成高效率的目标代码。
它可剔除重复的表达式计算,采用循环求值法、快速的算术运算,以及采用一些能够提高目标代码运行效率的算法来提高效率。
对于效率至上的应用来说,这样的编译程序是很有效的。
(3)影响存储效率的因素
在大中型计算机系统中,存储限制不再是主要问题。
在这种环境下,对内存采取基于操作系统的分页功能的虚拟存储管理,给软件提供了巨大的逻辑地址空间。
这时,存储效率与操作系统的分页功能直接有关,并不是指要使所使用的存储空间达到最少。
采用结构化程序设计,将程序功能合理分块,使每个模块或一组密切相关模块的程序体积大小与每页的容量相匹配,可减少页面调度,减少内外存交换,提高存储效率。
在微型计算机系统中,存储容量对软件设计和编码的制约很大。
因此要选择可生成较短目标代码且存储压缩性能优良的编译程序,有时需采用汇编程序。
通过程序员富有创造性的努力,提高软件时间与空间效率。
提高存储效率的关键是程序的简单性。
(4)影响输入/输出的因素
输入/输出可分为两种类型:
一种是面向人(操作员)的输入/输出;一种是面向设备的输入/输出。
如果操作员能够十分方便、简单地录入输入数据,或者能够十分直观、一目了然地了解输出信息,则可以说面向人的输入/输出是高效的。
至于面向设备的输入/输出,分析起来比较复杂。
从详细设计和程序编码的角度来说,可以提出一些提高输入/输出效率的指导原则:
输入/输出的请求应当最小化;
对于所有的输入/输出操作,安排适当的缓冲区,以减少频繁的信息交换。
对辅助存储(例如磁盘),选择尽可能简单的,可接受的存取方法;
对辅助存储的输入/输出,应当成块传送;
对终端或打印机的输入/输出,应考虑设备特性,尽可能改善输入/输出的质量和速度;
任何不易理解的,对改善输入/输出效果关系不大的措施都是不可取的;
任何不易理解的所谓“超高效”的输入/输出是毫无价值的;
好的输入/输出程序设计风格对提高输入/输出效率会有明显的效果。
4.程序设计语言
程序编码阶段的任务是将软件的详细设计转换成用程序设计语言实现的程序代码。
因此,程序设计语言的性能和设计风格对于程序设计的效能和质量有着直接的关系。
(1)程序设计语言特性的比较
①软件心理学的观点
因为从设计到编码的转换基本上是人的活动,因此语言的性能对程序员的心理影响,将对转换产生重大影响。
程序员总是希望选择简单易学、使用方便的语言,以减少程序出错率,提高软件可靠性。
从心理学的观点,影响程序员心理的语言特性有如下六种:
一致性:
它表示一种语言所使用符号的兼容程度、允许随意规定限制、以及允许对语法或语义破例的程度。
同是一个符号,给予多种用途,会引起许多难以察觉的错误。
二义性:
虽然语言的编译程序总是以一种机械的规则来解释语句,但读者则可能用不同的方式来理解语句。
例如,对于一个逻辑表达式A≥“0”andA≤“9”,读者可能对这个逻辑表达式有不同的理解。
如果一个程序设计语言缺乏一致性和存在二义性,那么用这种语言编写出来的程序可读性就差,同时用这种语言编程也容易出错。
简洁性(紧凑性):
表示程序员为了用该语言编写程序,必须记忆的有关编码的信息量。
可用语言支持块结构和结构化程序的能力、可使用的保留字和缩写字的种类、数据类型的种类和缺省说明、算术运算符和逻辑运算符的种类、系统内标准函数的数目等来衡量。
遗憾的是,语言的简洁性与程序的一致性常常是抵触的。
局部性:
指程序设计语言的联想(综合)特性。
综合的特性使人们能够对事物从整体上进行记忆和识别。
在编码过程中,由语句组合成模块,由模块组装为程序体系结构,并在组装过程中实现模块的高内聚和低耦合,可使程序的局部性加强。
线性:
指程序的联想(顺序)特性。
人们总是习惯于按逻辑线性序列理解程序。
如果程序中线性序列和逻辑运算较多,会提高可读性。
如果存在大量的分支和循环,就会破坏顺序状态,增加理解上的困难。
直接实现结构化程序可提高程序的线性特性。
传统:
人们学习一种新的程序设计语言的能力受到传统的影响。
具有Pascal基础的程序人员在学习C语言时不会感到困难,因为C保持了Pascal所确立的传统语言特性。
但是要求同一个人去学习APL或者LISP这样一些语言,传统就中断了。
②软件工程的观点
从软件工程观点,程序设计语言的特性应着重考虑软件开发项目的需要。
为此,对于程序编码,有如下一些工程上的性能要求:
详细设计应能直接地容易地翻译成代码程序:
把设计变为程序的难易程度,反映了程序设计语言与设计说明相接近的程度。
所选择的程序设计语言是否具有结构化的构造,复杂的数据结构,专门的输入/输出能力,位运算和串处理的能力,直接影响到从详细设计变换到代码程序的难易程度,以及特定软件开发项目的可实现性。
源程序应具有可移植性:
源程序的可移植性通常有三种解释:
①对源程序不做修改或少做修改就可以实现处理机上的移植或编译程序上的移植;②即使程序的运行环境改变(例如,改用一个新版本的操作系统),源程序也不用改变;③源程序的许多模块可以不做修改或少做修改就能集成为功能性的各种软件包,以适应不同的需要。
为改善软件的可移植性,主要是使语言标准化。
在开发软件时,应严格地遵守ISO或ANSI、GB的标准,而不要去理会特定编译器提供的非标准特性。
编译程序应具有较高的效率。
尽可能应用代码生成的自动工具:
有效的软件开发工具是缩短编码时间,改善源代码质量的关键因素。
使用带有各种有效的自动化工具的“软件开发环境”,支持从设计到源代码的翻译等各项工作,可以保证软件开发获得成功。
可维护性:
源程序的可读性,语言自身的文档化特性(涉及标识符的允许长度、标号命名、数据类型的丰富程度、控制结构的规定等)是影响到可维护性的重要因素。
③程序设计语言的技术性能
在计划阶段,极少考虑程序语言的技术特性。
但在选定资源时,要规划将要使用的支撑工具,就要确定一个具体的编译器或者确定一个程序设计环境。
如果软件开发组的成员对所要使用的语言不熟悉,那么在成本及进度估算时必须把学习的工作量估算在内。
一旦确定了软件需求,待选用的程序语言的技术特性就显得非常重要了。
如果需要复杂的数据结构,就要仔细衡量有哪些语言能提供这些复杂的数据结构。
如果首要的是高性能及实时处理的能力,就可选用适合于实时应用的语言或效率高的语言。
如果该应用有许多输出报告或繁杂的文件处理,最好是根据软件的要求,选定一种适合于该项工作的语言。
软件的设计质量与程序设计语言的技术性能无关(面向对象设计例外)。
但在实现软件设计转化为程序代码时,转化的质量往往受语言性能的影响。
因而也会影响到设计方法。
语言的技术性能对测试和维护的影响是多种多样的。
例如,直接提供结构化构造的语言有利于减少循环带来的复杂性(即McCabe复杂性),使程序易读、易测试、易维护。
另一方面,语言的某些技术特性却会妨碍测试。
例如,在面向对象的语言程序中,由于实行了数据封装,使得监控这些数据的执行状态变得比较困难;由于建立了对象类的继承结构,使得高内聚、低耦合的要求受到破坏,增加了测试的困难。
此外,只要语言程序的可读性强,而且可以减少程序的复杂性,这样的程序设计语言对于软件的维护就是有利的。
总之,通过仔细地分析和比较,选择一种功能强而又适用的语言,对成功地实现从软件设计到编码的转换,提高软件的质量,改善软件的可测试性和可维护性是至关重要的。
(2)程序设计语言的分类
目前,用于软件开发的程序设计语言已经有数百种之多,对这些程序设计语言的分类有不少争议。
同一种语言可以归到不同的类中。
从软件工程的角度,根据程序设计语言发展的历程,可以把它们大致分为4类。
①从属于机器的语言(第一代语言):
它是由机器指令代码组成的语言。
对于不同的机器就有相应的一套机器语言。
用这种语言编写的程序,都是二进制代码的形式,且所有的地址分配都是以绝对地址的形式处理。
存储空间的安排,寄存器、变址的使用都由程序员自己计划。
因此使用机器语言编写的程序很不直观,在计算机内的运行效率很高但编写出的机器语言程序其出错率也高。
②汇编语言(第二代语言):
汇编语言比机器语言直观,它的每一条符号指令与相应的机器指令有对应关系,同时又增加了一些诸如宏、符号地址
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 软件工程 中文 讲义
![提示](https://static.bdocx.com/images/bang_tan.gif)