软件工程理论与实践课件:第7章 程序的编写
文档格式:PPT| 95 页|大小 705KB|积分 20|2022-11-07 发布|文档ID:167992511

Reasons:Others are able to understand what you have written,why you have written it and how it fits in with their work.让别人理解你写了什么,为什么写以及它同工作是如何配合的。Standards for you 个人的标准 Help you to organize your thoughts and avoid mistakes.Standardized documentation helps in locating faults and making changes,because it clarifies which sections of yourprogram perform which functions.帮你组织思想,避免错误。标准化的文档还有助于查找错误的位置并作出改动。Help in translating designs to code.By structuring code according to standards,you maintain the correspondence between design components and code components.有助于你将设计转化成代码,维持设计组件何代码组件之间的一致性。Standards for others 其他人的标准 You organize,format,and document your code to make it easy for other to understand what it does and how it works.组织、排版及编写代码文档,使其他人容易理解软件做什么及如何运行。Matching design with implementation设计与实现的匹配 The most critical standard is the need for a direct correspondence between the program design components and the program code components.最关键的标准就是需要在程序设计组件和程序代码组件之间有直接的对应关系.(系统的一般目的是在整个软件生命周期中保持一致,设计和代码之间的一致性是基本问题.)/*Statement of function:函数功能*Component name:组件名*Programmer:程序员*Version:版本*Procedure Invocation:过程调用*Input Parameters:输入参数*Output Parameters:输出参数*/Major aspects of programming编程的主要方面:control structures 控制结构Algorithms 算法data structures 数据结构 Many of control structures for a component are suggested by the architecture and design.It is important for your program structure to reflect the designs control structure.体系结构和设计提出了很多组件的控制结构,程序结构反映设计的控制结构是非常重要的。Many guidelines and standards suggest that the code be written so you can read a component easily from the top down.许多指导方针和标准建议代码应写成便于从上至下阅读一个组件的样式。结构程序设计的概念最早由E.W.Dijkstra在1965年提出,他指出:“可以从高级语言中取消GOTO语句”,“程序的质量与程序中所包含的GOTO语句的数量成反比”。1966年Bohm和Jacopini证明了,只用3种基本的控制结构就能实现任何单入口单出口的程序。这3种基本的控制结构是“顺序”、“选择”和“循环”。1968年Dijkstra再次建议,1971年IBM成功地应用结构程序设计在纽约时报信息库管理系统和美国宇航局飞行模拟实验中。结构程序设计的经典定义如下所述:“如果一个程序的代码块仅仅通过顺序、选择和循环这3种基本控制结构进行连接,并且每个代码块只有一个入口和一个出口,则称这个程序是结构化的。”对经典定义的扩充:“结构程序设计是尽可能少用GOTO语句的程序设计方法。最好仅在检测出错误时才使用GOTO语句,而且应该总是使用前向GOTO语句。”经典的结构程序设计:如果只允许使用顺序、IF-THEN-ELSE型分支和DO-WHILE型循环这3种基本控制结构实现单入口单出口的程序 扩展的结构程序设计:如果除了上述3种基本控制结构之外,还允许使用DO-CASE型多分支结构和DO-UNTIL型循环结构 修正的结构程序设计:如果再加上允许使用LEAVE(或BREAK)结构 Generality is a virtue,do not make your code more specialized than it needs to be.Dont make your components so general that performance and understanding are affected.一般性是优点,不要让你的代码太特殊。不要让组件过分全面,从而影响性能和理解。Efficiency may have hidden costs cost to write the code faster cost to test the code cost to understand the code cost to modify the code效率可能隐含代价(成本)写更快代码的代价测试代码的代价理解代码的代价修改代码的代价“Index=3*i+2*j+k”better or worse?Keeping the program simple 保持程序简单易懂 Using a data structure to determine a program structure.用数据结构确定程序结构 For example,recursive.P315.Table 7.1.Sample tax table.BracketBasePercent001010,00010001220,00022001530,00037001840,000550020 Localize input and output使输入输出局部化 Including pseudocode包括伪代码 Revise and rewrite,rather than patch修改与重写,胜于打补丁 Reuse 复用 Producer reuse 生产者复用 Consumer reuse 消费者复用 Consumer reuse消费者复用 Does the component perform the function or provide the data you need?组件是否能执行所需功能或者提供所需数据?If minor modification is required,is it less modification than building the component from scratch?如果要进行小的改动,改动工作是否比重新构造组件的工作要少?Is the component well-documented,so you can understand it without having to verify its implementation line by line?组件的文档是否完整,这样不用逐行阅读代码就能理解该组件?Is there a complete record of the components test and revision history,so you can be certain that it contains no faults?是否有完整的组件测试和修改历史的记录,这样你就能确信它不包含任何错误?Producer reuse生产者复用 Make your component general,using parameters and anticipating similar conditions to the ones in which your system will invoke your components.让组件比较通用,使用类似于将要调用该组件的系统中的参数和期望的类似条件。Separate dependencies so sections likely to need change are isolated from those that are likely to remain the same.将可能改变的部分和保持不变的部分的依赖关系分开。Keep the component interface general and well-defined.保证组件的接口全面而定义明确。Include information about any faults found and fixed.使用清楚的命令规范。Use clear naming conventions.记录数据结构和算法。Keep the communication and error-handing sections separate and easy to modify.保持通信和错误处理部分的独立性,而且要易于修改。We consider program documentation to be the set of written descriptions that explain to a reader what the programs do and how they do it.Internal documentation is descriptive material written directly within the code;all other documentation is external documentation.程序文档是向读者解释程序做什么以及如何实现的书面描述。内部文档是直接写在代码中的描述材料,所有其他的文档都是外部文档。Internal documentation header comment block other program comments meaningful variable names and statement labels format to enhance understanding document data External documentation describe the problem describe the algorithm describe the data内部文档头部注释块其他程序注释有意义的变量名和声明标示增进理解的格式记录数据外部文档描述问题描述算法描述数据 好程序的代码逻辑简明清晰、易读易懂:好程序的代码逻辑简明清晰、易读易懂:程序的内部文档程序的内部文档 数据说明数据说明 语句构造语句构造 输入输出方法输入输出方法 效率问题效率问题 标识符的命名:标识符的命名:标识符即符号名,包括模块名、变量名、常量名、标号名、子程标识符即符号名,包括模块名、变量名、常量名、标号名、子程序名、数据区名以及缓冲区名等。序名、数据区名以及缓冲区名等。这些名字应能反映它所代表的实际东西,应有一定实际意义。这些名字应能反映它所代表的实际东西,应有一定实际意义。(例例如,表示次数的量用如,表示次数的量用Times,表示总量的用,表示总量的用Total,表示平均值的用,表示平均值的用Average,表,表示和的量用示和的量用Sum等。等。)名字不是越长越好,应当选择精炼的意义明确的名字。名字不是越长越好,应当选择精炼的意义明确的名字。必要时可使用缩写名字,但这时要注意缩写规则要一致,并且要必要时可使用缩写名字,但这时要注意缩写规则要一致,并且要给每一个名字加注释。给每一个名字加注释。在一个程序中,一个变量只应用于一种用途。在一个程序中,一个变量只应用于一种用途。程序的注解程序的注解:夹在程序中的注释是程序员与日后的程序读者夹在程序中的注释是程序员与日后的程序读者之间通信的重要手段。之间通信的重要手段。注释决不是可有可无的。注释决不是可有可无的。一些正规的程序文本中,注释行的数量占到整一些正规的程序文本中,注释行的数量占到整个源程序的个源程序的13到到12,甚至更多。,甚至更多。注释分为序言性注释和功能性注释。注释分为序言性注释和功能性注释。序言性注释:序言性注释:通常置于每个程序模块的开头部分,它应当给出程序的整体说明,对通常置于每个程序模块的开头部分,它应当给出程序的整体说明,对于理解程序本身具有引导作用。有些软件开发部门对序言性注释做了于理解程序本身具有引导作用。有些软件开发部门对序言性注释做了明确而严格的规定,要求程序编制者逐项列出。明确而严格的规定,要求程序编制者逐项列出。有关项目包括:有关项目包括:程序标题;程序标题;有关本模块功能和目的的说明;有关本模块功能和目的的说明;主要算法;主要算法;接口说明:包括调用形式,参数描述,子程序清单;接口说明:包括调用形式,参数描述,子程序清单;有关数据描述:重要的变量及其用途,约束或限制条件,以及其它有关有关数据描述:重要的变量及其用途,约束或限制条件,以及其它有关信息;信息;模块位置:在哪一个源文件中,或隶属于哪一个软件包;模块位置:在哪一个源文件中,或隶属于哪一个软件包;开发简历:模块设计者,复审者,复审日期,修改日期及有关说明等。开发简历:模块设计者,复审者,复审日期,修改日期及有关说明等。功能性注释功能性注释:功能性注释嵌在源程序体中,用以描述其后的语句功能性注释嵌在源程序体中,用以描述其后的语句或程序段是在做什么工作,或是执行了下面的语句或程序段是在做什么工作,或是执行了下面的语句会怎么样。而不要解释下面怎么做。会怎么样。而不要解释下面怎么做。视觉组织视觉组织:空格、空行和缩进。空格、空行和缩进。恰当地利用空格,可以突出运算的优先性。恰当地利用空格,可以突出运算的优先性。自然的程序段之间可用空行隔开。自然的程序段之间可用空行隔开。缩进也叫做向右缩格或移行。它是指程序中的各行不缩进也叫做向右缩格或移行。它是指程序中的各行不必都在左端对齐,都从第一格起排列。这样做使程序必都在左端对齐,都从第一格起排列。这样做使程序完全分不清层次关系。完全分不清层次关系。对于选择语句和循环语句,把其中的程序段语句向右对于选择语句和循环语句,把其中的程序段语句向右做阶梯式移行。使程序的逻辑结构更加清晰。做阶梯式移行。使程序的逻辑结构更加清晰。在设计阶段已经确定了数据结构的组织及在设计阶段已经确定了数据结构的组织及其复杂性。在编写程序时,则需要注意数其复杂性。在编写程序时,则需要注意数据说明的风格。据说明的风格。为了使程序中数据说明更易于理解和维护,为了使程序中数据说明更易于理解和维护,必须注意以下几点:必须注意以下几点:数据说明的次序应当规范化;数据说明的次序应当规范化;说明语句中变量安排有序化;说明语句中变量安排有序化;使用注释说明复杂数据结构。使用注释说明复杂数据结构。数据说明的次序应当规范化:数据说明的次序应当规范化:数据说明次序规范化,使数据属性容易查找,也有利于测试,数据说明次序规范化,使数据属性容易查找,也有利于测试,排错和维护。排错和维护。原则上,数据说明的次序与语法无关,其次序是任意的。但出原则上,数据说明的次序与语法无关,其次序是任意的。但出于阅读、理解和维护的需要,最好使其规范化,使说明的先后于阅读、理解和维护的需要,最好使其规范化,使说明的先后次序固定。次序固定。例如,在类型说明中可按如下顺序排列:例如,在类型说明中可按如下顺序排列:整型量说明整型量说明实型量说明实型量说明字符量说明字符量说明逻辑量说明逻辑量说明 说明语句中变量安排有序化说明语句中变量安排有序化:当多个变量名在一个说明语句中说明时,应当对这当多个变量名在一个说明语句中说明时,应当对这些变量按字母的顺序排列。些变量按字母的顺序排列。例如,把例如,把integer size,length,width,cost,price写成写成integer cost,length,price,size,width 使用注释说明复杂数据结构使用注释说明复杂数据结构:如果设计了一个复杂的数据结构,应当使用注释来如果设计了一个复杂的数据结构,应当使用注释来说明在程序实现时这个数据结构的特点。说明在程序实现时这个数据结构的特点。例如例如,对对C的链表结构和的链表结构和Pascal中用户自定义的数据中用户自定义的数据类型,都应当在注释中做必要的补充说明。类型,都应当在注释中做必要的补充说明。在设计阶段确定了软件的逻辑流结构,但在设计阶段确定了软件的逻辑流结构,但构造单个语句则是编码阶段的任务。语句构造单个语句则是编码阶段的任务。语句构造力求简单、直接,不能为了片面追求构造力求简单、直接,不能为了片面追求效率而使语句复杂化。效率而使语句复杂化。下面是关于语句构造的一些启发规则:下面是关于语句构造的一些启发规则:1.在一行内只写一条语句。在一行内只写一条语句。2.避免采用过于复杂的条件测试。避免采用过于复杂的条件测试。3.尽量减少尽量减少“非非”条件的测试。条件的测试。IF NOT(CHAR9)THEN IF(CHAR=0)AND(CHAR=A)THEN IF(CHAR=Z)THENPRINT“This is a letter.”ELSE PRINT“This is not a letter.”15.不要单独进行浮点数的比较,而是采用不要单独进行浮点数的比较,而是采用|x0-x1|e16.尽可能用通俗易懂的伪码来描述程序的流程,然后再翻尽可能用通俗易懂的伪码来描述程序的流程,然后再翻译成必须使用的语言。译成必须使用的语言。对于语句构造,可以列举出很多实践总结对于语句构造,可以列举出很多实践总结出来的经验规则。但是再多的规则都不如出来的经验规则。但是再多的规则都不如经常反躬自省:经常反躬自省:“如果我不是编码的人,那么能如果我不是编码的人,那么能看懂它吗?看懂它吗?”关于输入和输出有下列的启发规则:关于输入和输出有下列的启发规则:1.对所有的输入数据都要进行检验,识别错误的输入,对所有的输入数据都要进行检验,识别错误的输入,以保证每个数据的有效性;以保证每个数据的有效性;2.检查输入项的各种重要组合的合理性,必要时报告输检查输入项的各种重要组合的合理性,必要时报告输入状态信息;入状态信息;3.使得输入的步骤和操作尽可能简单,并保持简单的输使得输入的步骤和操作尽可能简单,并保持简单的输入格式;入格式;4.输入数据时,应允许使用自由格式输入;输入数据时,应允许使用自由格式输入;5.应允许缺省值;应允许缺省值;6.输入一批数据时,最好使用输入结束标志,而不要由输入一批数据时,最好使用输入结束标志,而不要由用户指定输入数据数目;用户指定输入数据数目;7.在交互式输入输出时,要在屏幕上使用提示符在交互式输入输出时,要在屏幕上使用提示符 明确明确提示交互输入的请求,指明可使用选择项的种类和取提示交互输入的请求,指明可使用选择项的种类和取值范围。同时,在数据输入的过程中和输入结束时,值范围。同时,在数据输入的过程中和输入结束时,也要在屏幕上给出状态信息;也要在屏幕上给出状态信息;8.当程序设计语言对输入输出格式有严格要求时,应当程序设计语言对输入输出格式有严格要求时,应保持输入格式与输入语句要求的一致性;保持输入格式与输入语句要求的一致性;9.给所有的输出加注解,并设计输出报表格式。给所有的输出加注解,并设计输出报表格式。输入输出风格还受到许多其它因素的影响。如输入输入输出风格还受到许多其它因素的影响。如输入输出设备(例如终端的类型,图形设备,数字化转输出设备(例如终端的类型,图形设备,数字化转换设备等)、用户的熟练程度、以及通信环境等。换设备等)、用户的熟练程度、以及通信环境等。效率是性能要求,因此应该在需求分析阶效率是性能要求,因此应该在需求分析阶段确定效率方面的要求。段确定效率方面的要求。效率是靠好设计来提高的。效率是靠好设计来提高的。程序的效率和程序的简单程度是一致的,程序的效率和程序的简单程度是一致的,不要牺牲程序的清晰性和可读性来不必要不要牺牲程序的清晰性和可读性来不必要地提高效率。地提高效率。程序运行时间:源程序的效率直接由详细设计阶段确定的程序运行时间:源程序的效率直接由详细设计阶段确定的算法的效率决定,但是,写程序的风格也能对程序的执行算法的效率决定,但是,写程序的风格也能对程序的执行速度和存储器要求产生影响。速度和存储器要求产生影响。写程序之前先简化算术的和逻辑的表达式;写程序之前先简化算术的和逻辑的表达式;仔细研究嵌套的循环,以确定是否有语句可以从内层往外移;仔细研究嵌套的循环,以确定是否有语句可以从内层往外移;尽量避免使用多维数组;尽量避免使用多维数组;尽量避免使用指针和复杂的表;尽量避免使用指针和复杂的表;使用执行时间短的算术运算;使用执行时间短的算术运算;不要混合使用不同的数据类型;不要混合使用不同的数据类型;尽量使用整数运算和布尔表达式。尽量使用整数运算和布尔表达式。表达过程规格说明的工具叫做详表达过程规格说明的工具叫做详细设计工具:细设计工具:图形工具图形工具 表格工具表格工具 语言工具语言工具 程序流程图(程序流程图(Program Flow Chart)程序流程图本质上不是逐步求精的好工具,它程序流程图本质上不是逐步求精的好工具,它诱使程序员过早地考虑程序的控制流程,而不诱使程序员过早地考虑程序的控制流程,而不去考虑程序的全局结构。去考虑程序的全局结构。程序流程图中用箭头代表控制流,因此程序员程序流程图中用箭头代表控制流,因此程序员不受任何约束,可以完全不顾结构程序设计的不受任何约束,可以完全不顾结构程序设计的精神,随意转移控制。精神,随意转移控制。程序流程图不易表示数据结构。程序流程图不易表示数据结构。必须限制程序流程图只能使用五种基本的必须限制程序流程图只能使用五种基本的控制结构控制结构 需要对流程图所用的符号做出确切的规定需要对流程图所用的符号做出确切的规定 盒图(盒图(Box-Diagram)()(N-S图)图)Nassi和和Shneiderman提出提出N-SN-S图的嵌套定义形式图的嵌套定义形式 盒图有下述特点:盒图有下述特点:功能域功能域(即某个特定控制结构的作用域即某个特定控制结构的作用域)明确,明确,可以从盒图上一眼就看出来。可以从盒图上一眼就看出来。不可能任意转移控制。不可能任意转移控制。很容易确定局部和全程数据的作用域。很容易确定局部和全程数据的作用域。很容易表现嵌套关系,也可以表示模块的层次很容易表现嵌套关系,也可以表示模块的层次结构。结构。PAD(Problem Analysis Diagram)图:)图:1973年由日本日立公司发明年由日本日立公司发明 用二维树形结构的图来表示程序的控制流用二维树形结构的图来表示程序的控制流,设置了五种设置了五种基本控制结构的图式,并允许递归使用。基本控制结构的图式,并允许递归使用。PADPAD描述的示例描述的示例 PAD图的主要优点图的主要优点:使用表示结构化控制结构的使用表示结构化控制结构的PAD符号所设计出来的符号所设计出来的程序必然是结构化程序程序必然是结构化程序 PAD图所描绘的程序结构十分清晰图所描绘的程序结构十分清晰 用用PAD图表现程序逻辑,易读、易懂、易记图表现程序逻辑,易读、易懂、易记 容易将容易将PAD图转换成高级语言源程序,这种转换可图转换成高级语言源程序,这种转换可用软件工具自动完成用软件工具自动完成 即可用于表示程序逻辑,也可用于描绘数据结构即可用于表示程序逻辑,也可用于描绘数据结构 PAD图的符号支持自顶向下、逐步求精方法的使用图的符号支持自顶向下、逐步求精方法的使用 画出下列程序流程图对应的画出下列程序流程图对应的PAD图图ABwhile PBQAT 判定表判定表 当算法中包含多重嵌套的条件选择时,使用判当算法中包含多重嵌套的条件选择时,使用判定表能够清晰地表示复杂的条件组合与应做的定表能够清晰地表示复杂的条件组合与应做的动作之间的对应关系。动作之间的对应关系。判定表用于表示程序的静态逻辑。判定表用于表示程序的静态逻辑。在判定表中的条件部分给出所有的两分支判断在判定表中的条件部分给出所有的两分支判断的列表,动作部分给出相应的处理。的列表,动作部分给出相应的处理。要求将程序流程图中的多分支判断都改成两分要求将程序流程图中的多分支判断都改成两分支判断。支判断。判定表判定表 优点:能够简洁、无二义性地描述所有的处理优点:能够简洁、无二义性地描述所有的处理规则。规则。缺点:判定表表示的是静态逻辑,是在某种条缺点:判定表表示的是静态逻辑,是在某种条件取值组合情况下可能的结果,它不能表达加件取值组合情况下可能的结果,它不能表达加工的顺序,也不能表达循环结构,因此判定表工的顺序,也不能表达循环结构,因此判定表不能成为一种通用的设计工具。不能成为一种通用的设计工具。判定树判定树 判定树是判定表的变种。判定树是判定表的变种。优点:形式简单,比判定表更直观优点:形式简单,比判定表更直观 缺点:缺点:简洁性不如判定表简洁性不如判定表 画判定树时分枝的次序可能对最终画出的判定树的画判定树时分枝的次序可能对最终画出的判定树的简洁程度有较大影响简洁程度有较大影响 过程设计语言(过程设计语言(PDL)是用正文形式表示数据和处理过程的设计工具,是用正文形式表示数据和处理过程的设计工具,也被称为也被称为伪代码伪代码。PDL具有严格的具有严格的关键字外部语法关键字外部语法,用于定义控用于定义控制结构和数据结构;另一方面,制结构和数据结构;另一方面,PDL表示实际表示实际操作和条件的操作和条件的内部语法内部语法通常又是灵活自由的,通常又是灵活自由的,可以适应各种工程项目的需要。可以适应各种工程项目的需要。PROCEDURE spellcheck IS 查找错拼的单词查找错拼的单词 BEGIN split document into single words 把整个文档分离成单词把整个文档分离成单词 look up words in dictionary 在字典中查这些单词在字典中查这些单词 display words which are not in dictionary 显示字典中查不到的单词显示字典中查不到的单词 create a new dictionary 造一新字典造一新字典 END spellcheck PDL作为一种设计工具有如下一些优点:作为一种设计工具有如下一些优点:可以作为注释直接插在源程序中间。这样做能促使维可以作为注释直接插在源程序中间。这样做能促使维护人员在修改程序代码的同时也相应地修改护人员在修改程序代码的同时也相应地修改PDL注释,注释,因此有助于保持文档和程序的一致性,提高了文档的因此有助于保持文档和程序的一致性,提高了文档的质量质量 可以使用普通的正文编辑程序或文字处理系统,很方可以使用普通的正文编辑程序或文字处理系统,很方便地完成便地完成PDL的书写和编辑工作。的书写和编辑工作。已经有自动处理程序存在,而且可以自动由已经有自动处理程序存在,而且可以自动由PDL生成生成程序代码。程序代码。PDL的缺点是不如图形工具形象直观,描述复杂的缺点是不如图形工具形象直观,描述复杂的条件组合与动作间的对应关系时,不如判定表的条件组合与动作间的对应关系时,不如判定表清晰简单。清晰简单。定量度量程序复杂程度的方法的用途:定量度量程序复杂程度的方法的用途:把程序的复杂程度乘以适当常数即可估算出软把程序的复杂程度乘以适当常数即可估算出软件中错误的数量以及软件开发需要用的工作量;件中错误的数量以及软件开发需要用的工作量;定量度量的结果可以用来比较两个不同的设计定量度量的结果可以用来比较两个不同的设计或两个不同算法的优劣;或两个不同算法的优劣;程序的定量的复杂程度可以作为模块规模的精程序的定量的复杂程度可以作为模块规模的精确限度。确限度。McCabe方法根据程序控制流的复杂程度定量度方法根据程序控制流的复杂程度定量度量程序的复杂程度,这样度量出的结果称为量程序的复杂程度,这样度量出的结果称为程序程序的环形复杂度的环形复杂度。流图流图(也称为程序图):实质上是(也称为程序图):实质上是“退化了的退化了的”程序流程图,它仅仅描绘程序的控制流程,完全程序流程图,它仅仅描绘程序的控制流程,完全不表现对数据的具体操作以及分支或循环的具体不表现对数据的具体操作以及分支或循环的具体条件。条件。结点结点:用圆表示,代表一条或多条语句:用圆表示,代表一条或多条语句;边边:用箭头表示,一边必须终止于一个结点;:用箭头表示,一边必须终止于一个结点;区域区域:由边和结点围成的面积:由边和结点围成的面积;流程图、流图以及流程图、流图以及E、N、V的对应关系:的对应关系:121442 流程图、流图以及流程图、流图以及E、N、V的对应关系:的对应关系:332332 流程图、流图以及流程图、流图以及E、N、V的对应关系:的对应关系:7639101 3 6 2 4 7 8 5 11 1 2,3 4,5 1011 9 8 7 6 1 2 3 7b8 7a 5 6 4 a x y b 有了描绘程序控制流的流图之后,可以用有了描绘程序控制流的流图之后,可以用下述下述3种方法中的任何一种来计算环形复杂种方法中的任何一种来计算环形复杂度。度。流图中的区域数等于环形复杂度。流图中的区域数等于环形复杂度。流图流图G的环形复杂度的环形复杂度V(G)EN+2,其中,其中,E是流图中边的条数,是流图中边的条数,N是结点数。是结点数。流图流图G的环形复杂度的环形复杂度V(G)P+1,其中,其中,P是流是流图中判断的数目。图中判断的数目。环形复杂度的用途环形复杂度的用途 程序的环形复杂度取决于程序控制流的复杂程程序的环形复杂度取决于程序控制流的复杂程度,也即是取决于程序结构的复杂程度。度,也即是取决于程序结构的复杂程度。当程序内分支数或循环个数增加时,环形复杂当程序内分支数或循环个数增加时,环形复杂度也随之增加,因此它是对测试难度的一种定度也随之增加,因此它是对测试难度的一种定量度量,也能对软件最终的可靠性给出某种预量度量,也能对软件最终的可靠性给出某种预测。测。用来限制模块的最大行数。用来限制模块的最大行数。McCabe从大量的从大量的调查中发现,当调查中发现,当V(G)等于或大于等于或大于10时,对模块时,对模块进行充分的测试将变得非常困难。他主张将进行充分的测试将变得非常困难。他主张将10作为环域数的上限,并以此来限制模块的最大作为环域数的上限,并以此来限制模块的最大规模规模 几点说明:几点说明:环形复杂环形复杂度取决于程序控制结构的复杂度。当度取决于程序控制结构的复杂度。当程序的分支数目或循环数目增加时其复杂度也程序的分支数目或循环数目增加时其复杂度也增加增加。环形复杂。环形复杂度与程序中覆盖的路径条数有度与程序中覆盖的路径条数有关关。环形复杂环形复杂度是可加的。例如,模块度是可加的。例如,模块A的复杂度的复杂度为为3,模块,模块B的复杂度为的复杂度为4,则模块,则模块A与模块与模块B的的复杂度是复杂度是7。McCabe建议,对于复杂度超过建议,对于复杂度超过10的程序,应的程序,应分成几个小程序,以减少程序中的错误。分成几个小程序,以减少程序中的错误。Walsh用实例证实了这个建议的正确性。在用实例证实了这个建议的正确性。在McCabe复杂度为复杂度为10的附近,存在出错率的间的附近,存在出错率的间断跃变。断跃变。这种度量的缺点:这种度量的缺点:对于不同种类的控制流的复杂性不能区分;对于不同种类的控制流的复杂性不能区分;简单简单IF语句与循环语句的复杂性同等看待;语句与循环语句的复杂性同等看待;嵌套嵌套IF语句与简单语句与简单CASE语句的复杂性是一样语句的复杂性是一样的;的;模块间接口当成一个简单分支一样处理;模块间接口当成一个简单分支一样处理;一个具有一个具有1000行的顺序程序与一行语句的复杂行的顺序程序与一行语句的复杂性相同;性相同;StartDO WHILEC1EndCAEDBC2 它根据程序中运算符和操作数的总数来度它根据程序中运算符和操作数的总数来度量程序的复杂程度。量程序的复杂程度。运算符包括:运算符包括:算术运算符算术运算符 赋值符(赋值符(=或或:=)数组操作符数组操作符 逻辑运算符逻辑运算符 分界符分界符(,或(,或;或;或:)子程序调用符子程序调用符 关系运算符关系运算符 括号运算符括号运算符 循环操作符等循环操作符等特别地,成对的运算符,例如特别地,成对的运算符,例如“BEGINEND”、“FORTO”、“REPEAT UNTIL”、“WHILEDO”、“IFTHENELSE”、“()”等都当做单一运算符。等都当做单一运算符。程序长度,即预测的程序长度,即预测的Halstead长度长度 n1表示程序中不同运算符(包括保留字)的个数,表示程序中不同运算符(包括保留字)的个数,n2表示程序中不同运算对象的个数,表示程序中不同运算对象的个数,H表示表示“程序长度程序长度”,则有,则有 H=n1log2n1+n2log2n2 实际的实际的Halstead长度长度 设设N1为程序中实际出现的运算符总个数,为程序中实际出现的运算符总个数,N2为程序中实际出现的运算对象总个数,为程序中实际出现的运算对象总个数,N为实际的为实际的Halstead长度,则有长度,则有 N=N1+N2 经过多次验证,预测的经过多次验证,预测的Halstead长度与实长度与实际的际的Halstead长度是非常接近的。长度是非常接近的。程序的词汇表程序的词汇表 Halstead定义程序的词汇表为不同的运算符种定义程序的词汇表为不同的运算符种类数和不同的运算对象种类数的总和。若令类数和不同的运算对象种类数的总和。若令n为程序的词汇表,则有为程序的词汇表,则有 n=n1+n2 程序量程序量V,可用下式算得,可用下式算得 V=(N1+N2)log2(n1+n2)运算符计数运算对象计数可执行语句结束 7X6数组下标6I55J4IF()2N2DO222,2SAVE2程序结束111.LT.1n2=7 N2=22.GE.1GO TO 101n1=10 N1=28H=10 log2 10+7 log2 7=52.87N=N1+N2=28+22=50 V=(28+22)log2(10+7)=204 程序的潜在错误程序的潜在错误 Halstead度量可以用来预测程序中的错误。度量可以用来预测程序中的错误。认为程序中可能存在认为程序中可能存在的差错应与程序的容量成正比。因而预测公式为的差错应与程序的容量成正比。因而预测公式为 B=(N1+N2)log2(n1+n2)3000=V3000 B表示该程序的错误数。表示该程序的错误数。它表明程序中可能存在的差错它表明程序中可能存在的差错B应与程序量应与程序量V成正比。成正比。例如,一个程序对例如,一个程序对75个数据库项共访问个数据库项共访问1300次,对次,对150个个运算符共使用了运算符共使用了1200次,那么预测该程序的错误数:次,那么预测该程序的错误数:B=(1300+1200)log2(75+150)3000=6.5即预测该程序中可能包含即预测该程序中可能包含67个错误。个错误。Halstead的重要结论的重要结论 程序的实际程序的实际Halstead长度长度N可以由词汇表可以由词汇表n算算出。即使程序还未编制完成,也能预先算出程出。即使程序还未编制完成,也能预先算出程序的实际序的实际Halstead长度长度N,虽然它没有明确指虽然它没有明确指出程序中到底有多少个语句。出程序中到底有多少个语句。这个结论非常有用。经过多次验证,预测的这个结论非常有用。经过多次验证,预测的Halstead长度与实际的长度与实际的Halstead长度是非常接长度是非常接近的。近的。1979年,年,M.R.Woodward等人提出,用计等人提出,用计算程序图中交叉点的方法来度量程序的结算程序图中交叉点的方法来度量程序的结构复杂性。构复杂性。1 12 23 34 45 56 6100100200200 由程序图计算出来的交点数是一个介于下由程序图计算出来的交点数是一个介于下限和上限之间的值,并不总是唯一的。限和上限之间的值,并不总是唯一的。直接从程序计算出来的交点数只能有一个直接从程序计算出来的交点数只能有一个值。值。ABCABCS1S2ABCS1S2 改变程序中语句或程序图中节点的顺序,改变程序中语句或程序图中节点的顺序,会引起交点复杂度的变化,但环域复杂度会引起交点复杂度的变化,但环域复杂度总是保持不变。总是保持不变。假设如下表格所示的判定表代表某一加工假设如下表格所示的判定表代表某一加工的加工逻辑。为该加工设计一个模块,写的加工逻辑。为该加工设计一个模块,写出该模块的出该模块的FORTRAN程序,并计算它的交程序,并计算它的交点复杂度和环域复杂度点复杂度和环域复杂度规则规则123条件条件M=1TFFN=1TF动作动作调用调用SUBA1NJ加加1K加加1调用调用SUBB112306010020030023456K=911223456V(G)=9-8+2=31121002003002453K=3611224536V(G)=9-8+2=3 由此可见,交点复杂度对非结构化的反应由此可见,交点复杂度对非结构化的反应比环域复杂度更加灵敏,如果一个程序图比环域复杂度更加灵敏,如果一个程序图的交点复杂度的交点复杂度K=0,就表明这个程序已经完,就表明这个程序已经完全结构化了。全结构化了。
点击阅读更多内容
最新文档