资源描述
第四部分、结构化设计授课:王冲授课:王冲软件设计的任务1从分析过渡到设计2软件设计准则3度量模块独立性的标准4启 发 规 则5软件结构的图形工具6人机界面设计8过 程 设 计9过程设计工具10面向数据结构设计方法11结构化设计实例12面向数据流的设计方法7 经过需求分析阶段的工作,系统必须“做什么做什么”已经清楚了,现在是决定已经清楚了,现在是决定“怎样做怎样做”的时候了的时候了。为此,必须首先进行设计,软件设计的目标是设软件设计的目标是设计出符合用户需求的软件的模型计出符合用户需求的软件的模型。软件设计划包涵概要设计和详细设计这样两个阶段。1 1 软件设计的任务软件设计的任务1.1 1.1 概要设计的任务概要设计的任务 概要设计也称为总体设计或初步设计,概要设计也称为总体设计或初步设计,这个设计阶段主要有两项任务。这个设计阶段主要有两项任务。1 1、设计实现软件的最佳方案、设计实现软件的最佳方案 2 2、设计软件体系结构、设计软件体系结构 1.1.设计实现软件的最佳方案设计实现软件的最佳方案 概要设计过程首先设想实现目标系统的各种可能的方案,需求分析阶段得到的数据流图是设想各种可能方案的基础。一种常用的方法是,设想把数据流图中的处理分组(即画自动化边界)的各种可能方法。然后,分析员从设想出的这些供选择的方案中选取若干个合理的方案。最后,分析员应该综合分析对比所选取的各种合理方案的利弊,从中选出一个最佳方案,并且为推荐的这个最佳方案制定详细的实现计划。一旦用户和使用部门的负责人接受了分析员推荐的方案,就应该开始概要设计的第二项工作。方案选择 分析员应该考虑各种可能的实现方案,分析比较不同的物理实现方案,并力求从中选出最佳方案 通 常 至 少 选 取 低 成 本、中 等 成 本 及 高 成 本 的 三 种 方 案 分析员应该综合分析对比各种合理方案的利弊,推荐一个最佳的方案,并且为推荐的方案制定详细的实现计划2.2.设计软件体系结构设计软件体系结构 概要设计的第二项重要任务是设计软件的体系结构,也就是确定软件系统中每个程序是由哪些模块组成的,以及这些模块相互间的关系。通常,程序中的一个模块完成一个适当的子功能。应该把模块组织成良好的层次系统,顶层模块通过调用它的下层模块来实现程序的完整功能,顶层模块下面的每个模块再调用更下层的模块从而完成程序的一个子功能,最下层的模块完成最具体的功能。详细设计阶段的根本目标,是确定怎样具体地实现所要求的软件系统,应该得出对目标系统的精确描述,从而在编码阶段可以把这个描述直接翻译成用某种程序设计语言书写的程序。具体说来,详细设计主要有以下三项任务:过程设计,即设计软件体系结构中所包含的每个模块的实现算法;数据设计,即设计软件中需要的数据结构;接口设计,即设计软件内部各模块之间、软件与协作系统之间以及软件与使用它的人之间的通信方式。1.2 1.2 详细设计的任务详细设计的任务 详细设计阶段的任务还不是具体地编写程序,而是要设计出程序的“蓝图”,以后程序员将根据这个蓝图写出实际的程序代码。程序的“读者”有两个,那就是计算机和人。衡量程序的质量不仅要看它的逻辑是否正确,性能是否满足要求,更主要的是要看它是否容易阅读和理解。详细设计的目标不仅仅是逻辑上正确地实现每个模块的功能,更重要的是设计出的处理过程应该尽可能简明易懂。2 2 从分析过渡到设计从分析过渡到设计 系统分析的基本任务是定义用户需要的软件系统;系统设计的基本任务是设计实现目标系统的具体方案。虽然系统分析与系统设计的任务性质不同,但是两者却有十分密切的关系。软件设计必须依据用户对软件的需求来进行,因此,结构化分析的结果是结构化设计的最基本、最重要的输入信息。概要设计阶段的体系结构设计的任务是,确定程序由哪些模块组成以及这些模块相互间的关系。在需求分析阶段画出的数据流图,是进行体系结构设计的主要依据,为体系结构设计提供了最基本的输入信息。软件设计之所以如此重要,是因为设计是软件开发过程中决定软件产品质量的关键阶段。设计为我们提供了可以进行质量评估的软件表示(即软件模型),设计是我们把用户需求准确地转变为最终的软件产品的惟一方法。软件设计是后续的一切软件开发和维护步骤的基础,如果不进行设计,我们就会冒构造出不稳定的软件系统的风险:稍做改动这样的系统就可能崩溃;这样的系统很难维护,测试;将分析模型转换为设计将分析模型转换为设计数据字典数据字典数数据据流流图图实实体体关关系系图图状态转换图状态转换图加加工工规规格格说说明明控控制制规规 格格说说明明数数据据对对象象描描述述过程设计过程设计接口设计接口设计体系结构设计体系结构设计数据设计数据设计起点 需求分析阶段得出的DFD图是概要设计的极好的出发点 DFD图中的某些处理可以逻辑地归并在一个自动化边界内,作为一组;另一些处理可以放在另一个自动化边界内,作为另一组 这些自动化边界通常意味着某种实现策略 结构设计是概要设计阶段的主要工作 软件的结构决定了系统中每个程序是由哪些模块组成的 以及这些模块相互间的关系 软件结构包括程序的模块结构和数据的结构两部分 设计出初步的软件结构之后,分析员还应该从多方面改进软件结构,以便得到更合理的软件结构。从上面的叙述中不难看出,在详细设计之前先进行概要设计的必要性:分析员可以站在全局高度上,花较少的成本,在比较抽象的层次上分析对比多种可能的系统实现方案和多种可能的软件体系结构,从中选出最佳方案和最合理的软件结构,从而用较低的成本开发出较高质量的软件系统。3 3 软件设计准则软件设计准则 为了保证设计的质量,在软件设计过程中应为了保证设计的质量,在软件设计过程中应该遵循一些基本的准则(或称为原理)。该遵循一些基本的准则(或称为原理)。下面讲述在软件设计过程中应该遵循的基本下面讲述在软件设计过程中应该遵循的基本准则以及相关的概念。准则以及相关的概念。、信息隐藏、逐步求精、抽象、模块化与模块独立4321模块模块 是数据说明、可执行语句等程序对象的集合。它是单独命名且可通过名字来访问的,如过程、函数、子程序、宏等。模块一般具有如下基本属性:功能:描述该模块实现的功能;逻辑:描述模块内部怎么做;状态:该模块使用时的环境和条件。模块的外部特性是指模块名和参数表,其中的输入参数和输出参数,以及对程序及整个系统造成的影响 模块的内部特性是指完成其功能的程序代码和仅供该模块内部使用的数据。3.3.1 3.3.1 模块化与模块独立模块化与模块独立 模块化和模块独立,是关系非常密切的两条模块化和模块独立,是关系非常密切的两条设计准则。设计准则。1.1.模块化模块化 模块化就是把程序划分成独立命名且可独立模块化就是把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能,把这些访问的模块,每个模块完成一个子功能,把这些模块集成起来构成一个整体,可以完成指定的功模块集成起来构成一个整体,可以完成指定的功能满足用户的需求。能满足用户的需求。l模块化是软件结构设计的一个基本准则l高层模块隐蔽了细节,能够从整体上把握问题l而当我们需要时,也可以深入到较低的层次以了解进一步的细节l模块化提供给我们所需要的灵活性,如理解系统做什么、跟踪流经系统的数据流、定位系统的复杂部分。l尽管不像人们通常所想像的那样,对问题进行划分会奇迹般地把一个复杂的问题转换成简单问题的集合,然而,模块化允许我们孤立问题中最难以把握的部分,防止被不相关的功能和数据所困扰或误入歧途。假假设设C(X)C(X)表示表示问题难问题难度,度,E(X)E(X)表示表示问题问题解解决决工作量工作量如果如果 C(A)C(B)C(A)C(B)则则 E(A)E(B)E(A)E(B)故故 C(A+B)C(A)+C(B)C(A+B)C(A)+C(B)E(A+B)E(A)+E(B)E(A+B)E(A)+E(B)当模块数目增加时每个模块的规模将减小,开发单个模块需要的成本确实减少了;但是,随着模块数目增加,设计模块间接口所需要的工作量也将增加。根据这两个因素,得出了图中的总成本曲线。每个程序都相应地有一个最适当的模块数目M,使得系统的开发成本最小。模块化和软件成本的关系 虽然目前我们还不能精确地算出M的数值,但是在考虑程序模块化的时候,总成本曲线确实是有用的指南。采用模块化原理可以使软件结构清晰,不仅容易设计也容易阅读和理解。因为程序错误通常局限在有关的模块及它们之间的接口中,所以模块化使软件容易测试和调试,因而有助于提高软件的可靠性。因为变动往往只涉及少数几个模块,所以模块化能够提高软件的可修改性。模块化也有助于软件开发工程的组织管理,一个复杂的大型程序可以由许多程序员分工编写不同的模块,并且可以进一步分配技术熟练的程序员编写困难的模块。2.2.模块独立模块独立 是不是只要把程序划分成若干个模块,就可以获是不是只要把程序划分成若干个模块,就可以获得上述的模块化所带来的好处呢?事实并非如此。模得上述的模块化所带来的好处呢?事实并非如此。模块划分和组织得合理,能大大地提高软件的质量,反块划分和组织得合理,能大大地提高软件的质量,反之,软件质量不仅不会提高反而可能会下降。之,软件质量不仅不会提高反而可能会下降。怎样划分和组织模块才合理呢?一条指导模块划怎样划分和组织模块才合理呢?一条指导模块划分和组织的重要准则,就是分和组织的重要准则,就是“模块独立模块独立”。开发具有独立功能而且和其他模块之间没有过多开发具有独立功能而且和其他模块之间没有过多的相互作用的模块,就可以做到模块独立。换句话说的相互作用的模块,就可以做到模块独立。换句话说,希望这样设计软件结构,使得每个模块完成一个相,希望这样设计软件结构,使得每个模块完成一个相对独立的特定子功能,并且和其他模块之间的关系很对独立的特定子功能,并且和其他模块之间的关系很简单。简单。为什么模块的独立性很重要呢?主要有两条理由:第一,有效的模块化(即具有独立第一,有效的模块化(即具有独立的模块)的软件比较容易开发出来。的模块)的软件比较容易开发出来。这是由于能够分割功能而且接口可以简化,当许多人分工合作开发同一个软件时,这个优点尤其重要。第二,独立的模块比较容易测试第二,独立的模块比较容易测试和维护。和维护。这是因为相对说来,修改设计和程序需要的工作量比较小,错误传播范围小,需要扩充功能时能够“插入”模块。总之,模块独立是好设计的关键,而设计又是决定软件质量的关键环节。3.3.2 3.3.2 抽象抽象 人类在认识复杂现象的过程中使用的最强有力的思维工具是抽象。人们在实践中认识到,在现实世界中一定事物、状态或过程之间总存在着某些相似的方面(共性)。把这些相似的方面集中和概括起来,暂时忽略它们之间的差异,这就是抽象。或者说抽象就是抽出事物的本质特性而暂时不考虑它们的细节。3.3.3 3.3.3 逐步求精逐步求精 逐步求精是人类解决复杂问题时采用的基本技术,也是许多软件工程技术(例如,规格说明技术,设计和实现技术、测试和集成技术)的基础。可以把逐步求精定义为:“为了能集中精力解决主要问题而尽量推迟对问题细节的考虑。”事实上,可以把逐步求精看作是一项把一个时期内必须解决的种种问题按优先级排序的技术。逐步求精确保每个问题都将被解决,而且每个问题都在适当的时候解决,但是,在任何时候一个人都不需要同时处理7个以上知识块。求精实际上是细化过程。我们从在高抽象级别定义的求精实际上是细化过程。我们从在高抽象级别定义的功能陈述(或信息描述)开始。也就是说,该陈述仅仅概功能陈述(或信息描述)开始。也就是说,该陈述仅仅概念性地描述了功能或信息,但是并没有提供功能的内部工念性地描述了功能或信息,但是并没有提供功能的内部工作情况或信息的内部结构。求精要求设计者细化原始陈述,作情况或信息的内部结构。求精要求设计者细化原始陈述,随着每个后续求精(细化)步骤的完成而提供越来越多的随着每个后续求精(细化)步骤的完成而提供越来越多的细节。细节。抽象与求精是一对互补的概念。抽象使得设计者能抽象与求精是一对互补的概念。抽象使得设计者能够说明过程和数据,同时却忽略低层细节。事实上,可以够说明过程和数据,同时却忽略低层细节。事实上,可以把抽象看作是一种通过忽略多余的细节同时强调有关的细把抽象看作是一种通过忽略多余的细节同时强调有关的细节,而实现逐步求精的方法。求精则帮助设计者在设计过节,而实现逐步求精的方法。求精则帮助设计者在设计过程中揭示出低层细节。这两个概念都有助于设计者在设计程中揭示出低层细节。这两个概念都有助于设计者在设计演化过程中创造出完整的设计模型。演化过程中创造出完整的设计模型。3.3.4 3.3.4 信息隐藏信息隐藏 应用模块化原理时,自然会产生的一个问题是:“为了得到最好的一组模块,应该怎样分解软件”。信息隐藏原理指出:应该这样设计和确定模块,使得一个模块内包含的信息(过程和数据)对于不需要这些信息的模块来说,是不能访问的。实际上,应该隐藏的不是有关模块的一切信息,而是模块的实现细节。4.4.模块独立性标准模块独立性标准 软件系统中每个模块只涉及软件要求的具体的子功能,而和软件系统中其它的模块的接口是简单的 一个模块和其它模块的独立程度也是评价一个设计好坏的重要度量尺度。当一个模块的功能不是同其它模块紧密地联系在一起时,比较容易理解;其次,对个独立性较强的模块修改时不会或者较小的影响其他模块。耦合与内聚 内聚是模块功能强度的度量(即一个模块内部各个元素彼此结合的紧密程度),一个模块内聚程度越高,该模块内部各成分之间的关联也就越强。耦合是模块之间的互相连接的紧密程度的度量,耦合越松散,模块之间的联系就越小,模块的独立性就越强。1.内容耦合如果发生下列情形,两个模块之间就发生了内容耦合 (1)一个模块直接访问另一个模块的内部数据;(2)一个模块不通过正常入口转到另一模块内部;(3)两个模块有一部分程序代码重迭(只可能出现在汇编语言中);(4)一个模块有多个入口。模块AEntry1:Mov Entry2:Mov Entry3:Mov 模块BJMP Entry2(a)编语言模块多个入口 (b)B模块直接进入A模块耦合耦合2.公共耦合 若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。公共的数据环境可以是:全局数据结构 共享的通信区 内存的公共覆盖区 公共耦合的复杂程度随耦合模块的个数增加而显著增加。公共耦合举例公共耦合举例所有的公共所有的公共 耦合关系耦合关系A AE EB BC CD D6 6个模块共享一个模块共享一个个公共数据区公共数据区F 程序设计人员理解多个模块交叉共用公共环境的软件结构比较困难 某个模块究竟用了哪几个数据 某个数据究竟被哪几个模块使用 使用公共数据区的任模块如果出现错误,该错误可能会影响所有使用该数据区的模块 如果一个模块发生改变,要寻找哪些数据跟着发生变化相当困难公共耦合带来的复杂性公共耦合带来的复杂性3.外部耦合 一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合 外部耦合与公共耦合存在类似问题,都属于较强耦合 问题:外部耦合与公共耦合的异同?如果一个模块通过传送开关、标志、名字等控制信息,明显地控制选择另一模块的功能,就是控制耦合存在的问题:控制模块必须了解被控模块内部的逻辑关系 对被控模块的任何修改,都会影响控制模块。这种耦合实质上是在被控模块内部依据信号要求选择某一功能 模块A模块B过程1过程2过程3FlagFlag=1Flag=2Flag=3控制耦合举例控制耦合举例A A计算平均计算平均分分或最高分或最高分B B平均/最高成绩控制耦合举例控制耦合举例读入分数读入分数输出结果输出结果计算平均分计算平均分 计算最高分计算最高分平均平均/最高最高?调用逻辑性模块调用逻辑性模块 B B时,须先传递时,须先传递控制信号控制信号(平均分平均分 /最高分最高分),以选,以选择所需的操作。择所需的操作。控制模块必须知控制模块必须知道被控模块的内道被控模块的内部逻辑,增强了部逻辑,增强了相互依赖相互依赖.B B5.标记耦合(特征耦合)如果一组模块通过参数表传递信息,并只使用数据结构的部分数据 这个参数是:数据结构 字符串 记录 不是简单变量特征耦合举例特征耦合举例计算水电费计算水电费计算水费计算水费计算电费计算电费住户情况住户情况水费水费电费电费住户情况住户情况“住户情况住户情况”是一个数据结构是一个数据结构 如果一个模块访问另一个模块时,彼此之间是通过简单数据参数,来交换输入、输出信息的不是:控制参数 公共数据结构 外部变量6.数据耦合开发票开发票计算水费计算水费单价单价数量数量金额金额思考:思考:刚才的特征耦合例刚才的特征耦合例子如何变为数据耦合?子如何变为数据耦合?将特征耦合修改为数据耦合举例将特征耦合修改为数据耦合举例计算水电费计算水电费计算水费计算水费计算电费计算电费本月本月用水量用水量本月本月用电量用电量水费水费电费电费7.非直接耦合l 如果两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的,这就是非直接耦合l 这种耦合的模块独立性最强 两个模块没有直接关系两个模块没有直接关系(模快模快1 1和模快和模快2)2),模,模块独立性最强。块独立性最强。模块模块1 1模块模块2 2模块模块3 3模块模块4 41234567弱耦合弱耦合弱耦合中耦合较强耦合较强耦合强耦合原则原则:尽量使用数据耦合:尽量使用数据耦合少用控制耦合少用控制耦合限制公共耦合的范围限制公共耦合的范围坚决避免使用内容耦合坚决避免使用内容耦合高耦合的弊端高耦合的弊端 理解多软件结构比较困难。某个模块究竟用了哪几个数据?某个数据究竟被哪几个模块使用?使用公共数据区的任模块如果出现错误,该错误可能会影响所有使用该数据区的模块。如果一个模块发生改变,要寻找哪些数据跟着发生变化相当困难。这种软件结构难以修改。偶然内聚又称为巧合内聚。当模块内各部分之间没有联系,或者即使有联系,这种联系也很松散,则称这种模块为巧合内聚模块,它是内聚程度最低的模块。4.2 4.2 内聚内聚 模块内各部分间无联系模块内各部分间无联系ABCMMOVE O TO RREAD FILE FMOVE S TO T模块模块M中的三个语句没有任何联系中的三个语句没有任何联系缺点:缺点:可理解性差,可理解性差,可修改性差可修改性差例例:这种模块把几种相关的功能组合在一起,每次被调用时,由传送给模块的判定参数来确定该模块应执行哪一种功能 逻辑内聚缺点:不易修改增强了耦合程度(控制耦合)效率低2.逻辑内聚 时间内聚又称为经典内聚。这种模块大多为多功能模块,但模块的各个功能的执行与时间有关,通常要求所有功能必须在同一时间段内执行。例如:初始化模块和终止模块。3.时间内聚函数A(T时间)函数B(T+t时间)函数C(T-t时间)一个模块内部的处理成分是相关的,而且这些处理必须以特定的次序执行 例如,把流程结构中的循环部分、判定部分、计算部分分成一个模块,这三个任务组成的模块是过程内聚模块。4.4.过程内聚过程内聚函数A函数B函数C过程内聚举例过程内聚举例建立方程组系数矩阵建立方程组系数矩阵全部任务纳入一个全部任务纳入一个模块,得到一过程模块,得到一过程性模块性模块高斯消去法高斯消去法回回 代代高斯消去法解题流程高斯消去法解题流程 如果一个模块内各功能部分都使用了相同的输入数据,或产生了相同的输出数据,则称之为通信内聚模块。通常,通信内聚模块是通过数据流图来定义的。5.5.通信内聚通信内聚函数A函数B函数C数据集通信内聚模块例一产生工产生工资报表资报表计算平计算平均工资均工资职工工职工工资记录资记录职工工职工工资报表资报表平均平均工资工资产生职工工资报表并计算平均工资模块产生职工工资报表并计算平均工资模块通信内聚模块例二通信内聚模块例二开领开领书单书单登记登记售书售书发票发票领书单领书单售售 书书登记表登记表文件文件删除删除修改修改6.6.顺序内聚顺序内聚 如果一个模块内的处理元素和同一功能密切相关,而且这些处理必须顺序执行(通常一个处理元素的输出数据作为下一个处理元素的输入数据)思考:顺序内聚与过程内聚的异同?一个模块中各个部分都是完成某一具体功能必不可少的组成部分或者说该模块中所有部分都是为了完成一项具体功能而协同工作,紧密联系,不可分割的 软件结构中应多使用功能内聚类型的模块7.7.功能内聚功能内聚模块的内聚性类型:模块的内聚性类型:低低 偶然内聚偶然内聚 内内 逻辑内聚逻辑内聚 聚聚 时间内聚时间内聚 性性 过程内聚过程内聚 通信内聚通信内聚 顺序内聚顺序内聚 高高 功能内聚功能内聚模模块块独独立立性性弱弱(功能分散功能分散)强强(功能单一功能单一)耦合、内聚与模块独立性的关系 耦合和内聚是评价软件系统设计质量好坏的标准,它们衡量系统设计中模块的划分是否合理、模块是否独立性强 模块的内聚度高,模块间耦合度低,模块的独立性就好,系统设计的质量也就好 模块独立性比较强的模块应是高内聚低耦合的模块。耦合与内聚的衡量 高内聚度,耦合弱,标志着模块的独立性强;反之,内聚度低,耦合就强,标志着模块的独立性差。内聚和耦合是密切相关的,模块的高内聚往往意味着模块间的松耦合。内聚和耦合都是进行模块化设计的有力参考指标。实践证明,内聚比耦合更重要,应该把更多注意力集中到提高模块的内聚度上来。5 好的软件设计特性 软件工程师们在开发计算机软件的长期实践中积累了丰富的经验,总结这些经验得出了一些启发规则。这些启发规则虽然不像前两节讲述的基本原理那样普遍适用,但是在许多场合仍然能给软件工程师有益的启示,往往能帮助他们找到改进软件设计提高软件质量的途径,因此有助于实现有效的模块化。几条常用的启发规则:1.1.改进软件结构提高模块独立性改进软件结构提高模块独立性 设计出软件的初步结构以后,应该审查分设计出软件的初步结构以后,应该审查分析这个结构,通过模块分解或合并,力求降低析这个结构,通过模块分解或合并,力求降低耦合提高内聚。耦合提高内聚。2.2.模块规模适中模块规模适中 一个模块的规模不应过大,最好能写在一页纸内。有人从心理学角度研究得知,当一个模块包含的语句数超过30句以后,模块的可理解程度迅速下降。过大的模块往往是分解不够充分,但是进一步分解必须符合问题本身的结构特点,一般说来,分解不应该以降低模块独立性为代价。过小的模块开销大于有效操作,并且模块数增加,将使系统接口复杂。因此过小的模块有时不值得单独存在,特别是当只有一个模块调用它时,通常可以把它合并到上一级模块中去。3.3.深度、宽度、扇出和扇入适中深度、宽度、扇出和扇入适中 深度表示软件结构中所控制的层数,它往往能粗略地标志一个系统的大小和复杂程度。深度和模块源代码长度之间应该有大致的对应关系,当然这个对应关系是在一定范围内变化的。如果层数过多则应该考虑管理模块是否过分简单了,能否适当合并。宽度是软件结构中模块数最多那一层的模块数目。一般说来,宽度越大系统越复杂。扇出是一个模块直接调用的下层模块数目。扇出过大往往意味着结构复杂,需要控制和协调过多的下层模块。扇出过小,意味着功能过分集中,也会增加模块内部的复杂程度。经验表明,一个好的软件系统的平均扇出通常是3或4,扇出的上限通常是59。扇出太大一般是因为缺乏中间层次,应该适当增加中间层次的控制模块。扇出太小时可以把下级模块进一步分解成若干个子功能模块,或者合并到它的上级模块中去。一个模块的扇入表明有多少个上层模块直接调用它,扇入越大则共享该模块的上层模块数目越多,这是有好处的,但是,不能违背模块独立性原则,而一味的追求高扇入。F深度=5深宽=8扇出=3扇出=4扇入=4 设计得好的软件结构通常顶层扇出比较高,中层设计得好的软件结构通常顶层扇出比较高,中层扇出较少,底层扇入到公共的实用模块中去(底层模扇出较少,底层扇入到公共的实用模块中去(底层模块有高扇入)。块有高扇入)。4.4.模块的作用域应该在控制域之内模块的作用域应该在控制域之内 模块的控制域定义为包括该模块及其下属模块 模块的作用域定义为受该模块内一个判定影响的模块及其下属模块 在一个设计得好的系统中,所有受判定影响的模块应该都从属于做出判定的那个模块,最好局限于做出判定的那个模块本身及它的直属下级模块。作用域超出控制域之后作用域超出控制域之后 A模块做出的判定同时影响模块G中的处理过程:这样的结构使得软件难于理解 为了使得A中的判定能影响G中的处理过程,通常需要在A中给一个标记设置状态以指示判定的结果,并且应该把这个标记传递给A和G的公共上级模块M,再由M把它传给G,使更多的模块间出现耦合关系 MABCGDEF5.5.降低模块接口的复杂性降低模块接口的复杂性 模块接口复杂是软件发生错误的一个主要原因。应该认真设计模块接口,使得信息传递简单并保持参数的一致性。求一元二次方程的根的模块,比较:QUAD_ROOT(TBL,X)QUAD_ROOT(A,B,C,ROOTl,ROOT2)6.6.设计单入口单出口的模块设计单入口单出口的模块 这条启发规则告诫软件工程师不要使模块间这条启发规则告诫软件工程师不要使模块间出现内容耦合,设计出的每一个模块都应该只有出现内容耦合,设计出的每一个模块都应该只有一个入口一个出口。当控制流从顶部进入模块并一个入口一个出口。当控制流从顶部进入模块并且从底部退出来时,软件是比较容易理解的,因且从底部退出来时,软件是比较容易理解的,因此也是比较容易维护的。此也是比较容易维护的。7.7.模块功能可以预测模块功能可以预测 一个模块可以当做一个黑盒子,只要输入的数据相同就产生同样的输出结果,这种模块的功能就是可以预测的 带有内部状态的模块的功能有时是不可预测的,因为它的输出取决于所处的状态,由于内部状态对于上级模块而言是不可见的,所以这样的模块既不易理解又难于测试和维护 6 6 描绘软件结构的图形工具描绘软件结构的图形工具 层次图用来描绘软件的层次结构。层次图中的矩形框表示模块,矩形框间的连线表示调用关系。正文加工系统的层次图HIPO图 HIPO图是美国IBM公司发明的“层次图加输入处理输出图”的英文缩写 每个方框都加了编号 与H图中每个方框相对应,应该有一张IPO图描绘模块的处理过程。图3.4 正文加工系统的H图 在结构图中通常还用带注释的箭头表示模块调用过程在结构图中通常还用带注释的箭头表示模块调用过程中来回传递的信息。如果希望进一步标明传递的信息是数中来回传递的信息。如果希望进一步标明传递的信息是数据还是控制信息,则可以利用注释箭头尾部的形状来区分:据还是控制信息,则可以利用注释箭头尾部的形状来区分:尾部是空心圆表示传递的是数据,实心圆表示传递的是控尾部是空心圆表示传递的是数据,实心圆表示传递的是控制信息。制信息。判定为真时调用A,为假时调用B模块M循环调用模块A、B、C 此外还有一些附加的符号,可以表示模块的选择调用此外还有一些附加的符号,可以表示模块的选择调用或循环调用。左图表示当模块或循环调用。左图表示当模块MM中某个判定为真时调用模中某个判定为真时调用模块块A A,为假时调用模块,为假时调用模块B B。右图表示模块。右图表示模块MM循环调用模块循环调用模块A A、B B和和C C。传入模块 从下属模块取得数据,经过某些处理,再将其传送给上级模块。传出模块 从上级模块获得数据,进行某些处理,再将其传送给下属模块。变换模块 它从上级模块取得数据,进行特定的处理,转换成其它形式,再传送回上级模块。协调模块 对所有下属模块进行协调和管理的模块。检查设计的正确性和评价模块独立性:传送的每个数据元素是否为完成模块功能所必须的;完成模块功能必须的每个数据元素是否都传送来了;所有数据元素是否都只和单一的功能有关;结构图上模块间的联系是否容易解释 SCSC图图层次图和层次图和SCSC图图 SC图不仅能够表示软件结构,而且还能够表示出模块接口间信息的传递关系,是一种较好的开发与维护人员通信的工具 层次图和SC图并不严格表示模块的调用次序,不指明什么时候调用下层模块 7 面向数据流的设计方法面向数据流的设计方法 面向数据流的设计方法的目标是给出设计软件结构的一个系统化的途径。在软件工程的需求分析阶段,信息流是一个关键考虑,通常用数据流图描绘信息在系统中加工和流动的情况。面向数据流的设计方法定义了一些不同的“映射”,利用这些映射可以把数据流图变换成软件结构。因为任何软件系统都可以用数据流图表示,所以面向数据流的设计方法理论上可以设计任何软件的结构。通常所说通常所说的结构化设计方法(简称的结构化设计方法(简称SDSD方法),也就是基方法),也就是基于数据流的设计方法于数据流的设计方法。3.7.1 3.7.1 概念概念 面向数据流的设计方法把信息流映射成软面向数据流的设计方法把信息流映射成软件结构,信息流的类型决定了映射的方法。信件结构,信息流的类型决定了映射的方法。信息流有下述两种类型。息流有下述两种类型。变换流变换流事务流事务流变换流示意图变换流示意图信息信息时间时间信息流信息流输入流输入流输出输出流流交换流交换流外部外部表示表示内部内部表示表示2.2.事务流事务流 基本系统模型意味着变换流,因此,原则上所有信基本系统模型意味着变换流,因此,原则上所有信息流都可以归结为这一类。但是,当数据流图具有和图类息流都可以归结为这一类。但是,当数据流图具有和图类似的形状时,这种数据流是似的形状时,这种数据流是“以事务为中心的以事务为中心的”,也就是,也就是说,数据沿输入通路到达一个处理说,数据沿输入通路到达一个处理T T,这个处理根据输入,这个处理根据输入数据的类型在若干个动作序列中选出一个来执行。这类数数据的类型在若干个动作序列中选出一个来执行。这类数据流应该划为一类特殊的数据流,称为事务流。图中的处据流应该划为一类特殊的数据流,称为事务流。图中的处理理T T称为事务中心,它完成下述任务:称为事务中心,它完成下述任务:(1 1)接收输入数据(输入数据又称为事务);)接收输入数据(输入数据又称为事务);(2 2)分析每个事务以确定它的类型;)分析每个事务以确定它的类型;(3 3)根据事务类型选取一条活动通路。)根据事务类型选取一条活动通路。图3.9 事务流3.设计过程设计过程图说明了使用面图说明了使用面向数据流方法逐步向数据流方法逐步设计的过程。设计的过程。图 面向数据流方法的设计过程 应该注意,应该注意,任何设计过程都任何设计过程都不是机械地一成不是机械地一成不变的,设计首不变的,设计首先需要人的判断先需要人的判断力和创造精神,力和创造精神,这往往会凌驾于这往往会凌驾于方法的规则之上。方法的规则之上。步步 骤骤 首先研究、分析和审查数据流图。从软件的需求规格说明中弄清数据流加工的过程。然后根据数据流图决定问题的类型。数据处理问题典型的类型有两种:变换型和事务型。针对两种不同的类型分别进行分析处理。由数据流图推导出系统的初始结构图。利用一些启发式原则来改进系统的初始结构图,直到得到符合要求的结构图为止。修改和补充数据词典。制定测试计划。3.7.2 3.7.2 变换分析变换分析 变换分析是一系列设计步骤的总称,经过这些步变换分析是一系列设计步骤的总称,经过这些步骤把具有变换流特点的数据流图按预先确定的模式映射骤把具有变换流特点的数据流图按预先确定的模式映射成软件结构。下面通过一个例子说明变换分析的方法。成软件结构。下面通过一个例子说明变换分析的方法。变换分析方法步骤变换分析方法步骤.检查并精化检查并精化DFDDFD图图 .确定输入流和输出流的边界,确定输入流和输出流的边界,区分有效(逻辑)区分有效(逻辑)输入、有效(逻辑)输出输入、有效(逻辑)输出,从而明确变换中心从而明确变换中心.完成完成“第一级映射第一级映射”,设计上层模块;,设计上层模块;.完成完成“第二级和下层的映射第二级和下层的映射”,设计输入、输出,设计输入、输出和中心变换部分的中、下层模块。和中心变换部分的中、下层模块。1.1.例子例子假设的仪表板将完成下述功能:假设的仪表板将完成下述功能:通过模通过模-数转换实现传感器和微处理机接口;数转换实现传感器和微处理机接口;在发光二极管面板上显示数据;在发光二极管面板上显示数据;指示每小时英里数(指示每小时英里数(milemileh h),行驶的里程,每加仑),行驶的里程,每加仑油行驶的英里数(油行驶的英里数(milemileGalGal)等等;)等等;指示加速或减速;指示加速或减速;超速警告:如果车速超过超速警告:如果车速超过55mile55mileh h,则发出超速警,则发出超速警告铃声。告铃声。在软件需求分析阶段应该对上述每条要求以及系统的在软件需求分析阶段应该对上述每条要求以及系统的其他特点进行全面的分析评价,建立起必要的文档资料,其他特点进行全面的分析评价,建立起必要的文档资料,特别是数据流图。特别是数据流图。2.2.设计步骤设计步骤第第1 1步步 复查基本系统模型。复查基本系统模型。复查的目的是确保系统的输入数据和输出数据符合实际。复查的目的是确保系统的输入数据和输出数据符合实际。第第2 2步步 复查并精化数据流图。复查并精化数据流图。假设在需求分析阶段产生的数字仪表板系统的数据流图如假设在需求分析阶段产生的数字仪表板系统的数据流图如图所示。图所示。这个数据流图对于软件结构设计的这个数据流图对于软件结构设计的“第一次分割第一次分割”而言已而言已经足够详细了,因此不需要精化就可以进行下一个设计步经足够详细了,因此不需要精化就可以进行下一个设计步骤。骤。图 数字仪表板系统的数据流图第第3 3步步 分析确定数据流的类型。分析确定数据流的类型。一般地说,一个系统中的所有信息流都可以认为是变一般地说,一个系统中的所有信息流都可以认为是变换流,但是,当遇到有明显事务特性的信息流时,建议采换流,但是,当遇到有明显事务特性的信息流时,建议采用事务分析方法进行设计。在这一步设计人员应该根据数用事务分析方法进行设计。在这一步设计人员应该根据数据流图中占优势的属性,确定数据流的全局特性。此外还据流图中占优势的属性,确定数据流的全局特性。此外还应该把具有和全局特性不同的特点的局部区域孤立出来,应该把具有和全局特性不同的特点的局部区域孤立出来,以后可以按照这些子数据流的特点精化根据全局特性得出以后可以按照这些子数据流的特点精化根据全局特性得出的软件结构。的软件结构。从图可以看出,数据沿着两条输入通路进入系统,从图可以看出,数据沿着两条输入通路进入系统,然后沿着五条通路离开,没有明显的事务中心。因此可以然后沿着五条通路离开,没有明显的事务中心。因此可以认为这个信息流具有变换流的总特征。认为这个信息流具有变换流的总特征。第第4步步 确定输入流和输出流的边界,从而确定输入流和输出流的边界,从而孤立出变换中心。孤立出变换中心。图3.12 具有边界的数据流图第5步 完成“第一级分解”。软件结构代表对控制的自顶向下的分配,所谓分解就是分配控制的过程。对于变换流的情况,数据流图被映射成一个特殊的软件结构,这个结构控制输入、变换和输出等信息处理过程。图说明了第一级分解的方法。位于软件结构最顶层的控制模块Cm协调下述从属的控制功能:输入信息处理控制模块输入信息处理控制模块Ca,协调对所有输入数据的接收;,协调对所有输入数据的接收;变换中心控制模块变换中心控制模块Ct,管理对内部形式数据的所有操作;,管理对内部形式数据的所有操作;输出信息处理控制模块输出信息处理控制模块Ce,协调输出信息的产生过程。,协调输出信息的产生过程。虽然图意味着一个三叉的控制结构,但是,对一个虽然图意味着一个三叉的控制结构,但是,对一个大型系统中的复杂数据流可以用两个或多个模块完成上大型系统中的复杂数据流可以用两个或多个模块完成上述一个模块的控制功能。应该在能够完成控制功能并且述一个模块的控制功能。应该在能够完成控制功能并且保持好的耦合和内聚特性的前提下,尽量使第一级控制保持好的耦合和内聚特性的前提下,尽量使第一级控制中的模块数目取中的模块数目取最小值。最小值。对于数字仪表板对于数字仪表板的例子,第一级分解的例子,第一级分解得出的结构如图得出的结构如图3.14所示。每个控制模块所示。每个控制模块的名字表明了为它所的名字表明了为它所控制的那些模块的功控制的那些模块的功能。能。图3.14 数字仪表板系统的第一级分解第第6 6步步 完成完成“第二级分解第二级分解”。所谓第二级分解就是把数据流图中的每个处理映射所谓第二级分解就是把数据流图中的每个处理映射成软件结构中一个适当的模块。完成第二级分解的方法是成软件结构中一个适当的模块。完成第二级分解的方法是,从变换中心的边界开始沿着输入通路向外移动,把输入,从变换中心的边界开始沿着输入通路向外移动,把输入通路中每个处理映射成软件结构中通路中每个处理映射成软件结构中CaCa控制下的一个低层控制下的一个低层模块;然后沿输出通路向外移动,把输出通路中每个处理模块;然后沿输出通路向外移动,把输出通路中每个处理映射成直接或间接受模块映射成直接或间接受模块CeCe控制的一个低层模块;最后控制的一个低层模块;最后把变换中心内的每个处理映射成受把变换中心内的每个处理映射成受CtCt控制的一个模块。图控制的一个模块。图表示进行第二级分解的普遍途径。表示进行第二级分解的普遍途径。第二级分解的方法 虽然图描绘了在数据流图中的处理和软件结构中的模块虽然图描绘了在数据流图中的处理和软件结构中的模块之间的一对一的映射关系,但是,不同的映射经常出现。之间的一对一的映射关系,但是,不同的映射经常出现。应该根据实际情况以及应该根据实际情况以及“好好”设计的标准,进行实际的第设计的标准,进行实际的第二级分解。二级分解。对于数字仪表板系统的例子,第二级分解的结果分别对于数字仪表板系统的例子,第二级分解的结果分别图3.16 未经精化的输入结构图3.17 未经精化的变换结构图3.18 未经精化的输出结构 这三张图表示对软件结构的初步设计结果。虽然图这三张图表示对软件结构的初步设计结果。虽然图中每个模块的名字表明了它的基本功能,但是仍然应该为中每个模块的名字表明了它的基本功能,但是仍然应该为每个模块写一个简要说明,描述:每个模块写一个简要说明,描述:进出该模块的信息(接口描述);进出该模块的信息(接口描述);模块内部的信息;模块内部的信息;过程陈述,包括主要判定点及任务等;过程陈述,包括主要判定点及任务等;对约束和特殊特点的简短讨论。对约束和特殊特点的简短讨论。当然,也可以用节中讲述的当然,也可以用节中讲述的IPOIPO表来描述每个模块表来描述每个模块。这些描述是第一代的设计规格说明,在这个设计时这些描述是第一代的设计规格说明,在这个设计时期进一步的精化和补充是经常发生的。期进一步的精化和补充是经常发生的。第第7 7步步 使用设计度量和启发式规则对第一次分割得到使用设计度量和启发式规则对第一次分割得到的软件结构进一步精化。的软件结构进一步精化。对第一次分割得到的软件结构,总可以根据模块独立原对第一次分割得到的软件结构,总可以根据模块独立原理进行精化。为了产生合理的分解,得到尽可能高的内聚理进行精化。为了产生合理的分解,得到尽可能高的内聚、尽可能松散的耦合,最重要的是,为了得到一个易于实、尽可能松散的耦合,最重要的是,为了得到一个易于实现、易于测试和易于维护的软件结构,应该对初步分割得现、易于测试和易于维护的软件结构,应该对初步分割得到的模块进行再分解或合并。到的模块进行再分解或合并。具体到数字仪表板的例子,对于从前面的设计步骤具体到数字仪表板的例子,对于从前面的设计步骤得到的软件结构,还可以做许多修改。下面是某些可能得到的软件结构,还可以做许多修改。下面是某些可能的修改:的修改:输入结构中的模块输入结构中的模块“转换成转换成r rmin”min”和和“收集收集SignalSignals”s”可以合并;可以合并;模块模块“确定加速减速确定加速减速”可以放在模块可以放在模块“计算计算milemileh”h”下面,以减少耦合;下面,以减少耦合;模块模块“加速减速显示加速减速显示”可以相应地放在模块可以相应地放在模块“显示显示milemileh”h”的下面。的下面。精化后的数字仪表板系统的软件结构 上述七个设计步骤的目的是,开发出软件的上述七个设计步骤的目的是,开发出软件的整体表示。也就是说,一旦确定了软件结构就可整体表示。也就是说,一旦确定了软件结构就可以把它作为一个整体来复查,从而能够评价和精以把它作为一个整体来复查,从而能够评价和精化软件结构。在这个时期进行修改只需要很少的化软件结构。在这个时期进行修改只需要很少的附加工作,但是却能够对软件的质量特别是软件附加工作,但是却能够对软件的质量特别是软件的可维护性产生深远的影响。的可维护性产生深远的影响。变换映射注意事项 在设计下层模块时,应考虑模块的耦合和内聚问题,以提高初始结构图的质量 在模块划分时,一个模块的直接下属模块一般在5个左右。如果直接下属模块超过10个,可设立中间层次 如果出现了以下情况,就停止模块的功能分解 当模块不能再细分为明显的子任务时;当分解成用户提供的模块或程序库的子程序时;当模块的界面是输入输出设备传送的信息时;当模块不宜再分解得过小时。举例用户信息输入 虽然在任何情况下都可以使用变换分析方法设虽然在任何情况下都可以使用变换分析方法设计软件结构,但是在数据流具有明显的事务特点计软件结构,但是在数据流具有明显的事务特点时,也就是有一个明显的时,也就是有一个明显的“发射中心发射中心”(事务中(事务中心)时,还是以采用事务分析方法为宜。心)时,还是以采用事务分析方法为宜。事务分析的设计步骤和变换分析的设计步骤事务分析的设计步骤和变换分析的设计步骤大部分相同或类似,主要差别仅在于由数据流图大部分相同或类似,主要差别仅在于由数据流图到软件结构的映射方法不同。到软件结构的映射方法不同。3.7.3 3.7.3 事务分析事务分析 由事务流映射成的软件结构包括一个接收分支和一个发送分支。映射出接收分支结构的方法和变换分析映射出输入结构的方法很相像,即从事务中心的边界开始,把沿着接收流通路的处理映射成模块。发送分支的结构包含一个调度模块,它控制下层的所有活动模块;然后把数据流图中的每个活动流通路映射成与它的流特征相对应的结构。事务分析的映射方法典型的事务型典型的事务型SCSC图图 调度层就是映射成的调度模块,负责发送事务 事务层的各模块对应每个动作路径 操作层和细节层是动作路径中各功能模块的细分 变换分析是软件系统结构设计的主要方法 一般,一个大型的软件系统是变换型结构和事务型结构的混合结构 通常利用以变换分析为主,事务分析为辅的方式进行软件结构设计 对于一个大系统,常常把变换分析和事务分析对于一个大系统,常常把变换分析和事务分析应用到同一个数据流图的不同部分,由此得到应用到同一个数据流图的不同部分,由此得到的子结构形成的子结构形成“构件构件”,可以利用它们构造完,可以利用它们构造完整的软件结构。整的软件结构。事务型和变换型的联系 应该在设计的早期阶段尽量对软件结构进行精化。可以导出不同的软件结构,然后对它们进行评价和比较,力求得到“最好”的结果。这种优化的可能,是把软件结构设计和过程设计分开的真正优点之一。注意,结构简单通常既表示设计风格优雅,又表明效率高。设计优化应该力求做到在有效的模块化的前提下使用最少量的模块,以及在能够满足信息要求的前提下使用最简单的数据结构。3.7.4 3.7.4 设计优化设计优化l 一个完整的模块应当有以下几部分:l 执行规定的功能的部分;l 出错处理的部分。当模块不能完成规定的功能时,必须回送出错标志,出现例外情况的原因。l 如果需要返回一系列数据给它的调用者,在完成数据加工或结束时,应当给它的调用者返回一个结束状态标志。设计优化应该力求做到在有效的模块化的前提下使用最少量的模块,以及在能够满足信息要求的前提下使用最简单的数据结构 完全相似:在结构上完全相似,可能只是在数据类型上不一致。此时可以采取完全合并的方法 局部相似:找出其相同部分,分离出去,重新定义成一个独立的下一层模块。还可以与它的上级模块合并。
展开阅读全文