软件工程第四讲教案

更新时间:2024-06-08 09:43:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

教案首页

周次 日期 课时序 课 题 教学目的 要 求 重 点 难 点 教学过程 设 计 及 时间分配 软件总体设计 理解软件总体设计目标;掌握软件总体设计的手段与方法,理解模块独立性概念;理解模块化概念 软件总体设计目标、模块化 软件总体设计的手段与方法;模块独立性 第一章 软件总体设计(2*45‘) 第一节 总体设计的任务与步骤(15‘) 第二节 软件设计原则(15‘) 第三节 面向数据流的设计方法(30‘) 第四节 面向数据结构的分析设计方法(25‘) 第五节 总体设计文档评审(5‘) 教学场所 或教学方法 作 业 使用 教具 课 后 记 授课教师

1

第四章 软件总体设计

问题定义、可行性研究和需求分析构成了软件计划阶段,在这个阶段确定了需要做什么,解决了系统开发目标,系统需求规格。而软件开发阶段的任务是回答系统如何实现的问题。软件开发阶段包括总体设计、详细设计、编码和测试等。在总体设计中有两个主要任务: ① 将系统划分成物理元素,即程序、文件、数据库、文档等。 ② 设计软件结构,即将需求规格转换为软件体系结构、划分出程序的模块组成、模块间的相互关系 、确定数据结构和算法等。

总体设计过程首先寻找实现目标系统的各种不同的方案,需求分析阶段得到的数据流图是设想的各种方案的基础与根据。然后从这些可供选择的方案中选取若干个合理的方案,为每个合理的方案都准备一份系统流程图、列出组成系统的所有物理元素、进行成本/效益分析,并且制定实现这个方案的进度计划。应该综合分析比较这些合理的方案,从中选出一个最佳方案向用户和使用部门负责人推荐。如果用户和使用部门的负责人接受了推荐的方案,应该进一步为这个最佳方案设计软件结构。通常,设计出初步的软件结构后还要进一步改进,从而得到更合理的结构,进行必要的数据库设计,确定测试要求并且制定测试计划。 4.1 总体设计的任务与步骤 4.1.1 总体设计任务

1.系统分析员审查软件计划、软件需求分析文档,提出最佳推荐方案,用系统流程图描述,组成系统物理元素清单,成本效益分析,系统的进度计划,供专家审定,审定后进入设计。

2.划分功能模块,将软件功能需求分配给所划分的最小单元模块。确定模块间的联系,确定数据结构、文件结构、数据库模式,确定测试方法与策略。 3.编写总体设计说明书,用户手册,测试计划,选用相关的软件工具来描述软件结构,结构图是经常使用的软件描述工具。选择分解功能与划分模块的设计原则等。 4.1.2 总体设计的过程 S1:设计系统方案

为了实现要求的系统,系统分析员应该提出并分析各种可能的方案,并且从中选出最佳的方案。而在分析阶段提供的用数据流图描述逻辑模型是总体设计的出发点。数据流图中的某些处理可以逻辑地归并在一个边界内作为一组,另一些处理可以放在另一个边界内作为另一组。这些边界代表某种实现策略。在可供选择的多种方案中,进一步设想与选择较好的系统实现方案。这个方案仅是边界的取舍,抛弃技术上行不通的方法,留下可能的实现策略,但并不评价这个方案。

2

S2:选取合理的方案

分析员在通过问题定义,可行性研究和需求分析后,产生了一系列可供选择的方案,从中选取低成本,中成本,高成本三种方案,必要时再进一步征求用户意见。并准备好系统流程图,系统的物理元素清单(即构成系统的程序、文件、数据库、人工过程,文档等),成本效益分析,实现系统的进度计划。 S3:推荐最佳实施方案

综合分析各种方案的优缺点,推荐最佳方案,并做详细的实现进度计划。用户与有关技术专家认真审查分析员推荐的方案,然后提交使用部门负责人审批,审批接受分析员推荐的最佳实施方案后,才能进入软件结构设计。 S4:功能分解

要把复杂的功能进一步分解成简单的功能,遵循模块划分独立性原则(即做到模块功能单一,模块与外部联系很弱,仅有数据联系),使划分过的模块的功能对大多数程序员而言都是易懂的。功能的分解导致对数据流图的进一步细化,并选用相应图形工具来描述。 S5:软件结构设计

用层次图(HC)、结构图(系统结构)来描述模块组成的层次系统,即反映了软件结构。当数据流图细化到适当的层次,由结构化的设计方法(SD)可以直接映射出结构图(系统结构)。 S6:数据库设计、文件结构的设计

根据系统的数据要求,确定系统的数据结构、文件结构。对需要使用数据库的应用领域,分析员再进一步根据系统数据要求完成数据库的模式设计,确定数据库物理数据的结构约束。进行数据库子模式设计,设计用户使用的数据视图。再做数据库完整性与安全性设计,改进与优化模式和子模式(用户使用的数据库视图)的数据存取。 S7:制定测试计划

为保证软件的可测试性,软件设计一开始就要考虑软件测试问题。这个阶段的测试计划仅从I/O功能做的黑盒法测试计划,详细设计时才能做详细的测试用例与计划。 S8:编写总体设计文档

·用户手册。对需求分析阶段编写的用户手册进一步修订。 ·测试计划。对测试的计划、策略、方法和步骤提出明确的要求。 ·详细项目开发实现计划。给出系统目标、总体设计、数据设计、处理方式设计、运行设计和出错设计等。

·数据库设计结果。使用的数据库简介数据模式设计和物理设计等。 S9:审查与复审总体设计文档。

3

根据总体设计阶段的结果,修改更正在需求分析阶段产生的初步的用户手册。 总体设计过程如图 4-1所示。

图 4-1 总体设计过程

4.2 软件设计的原则

软件设计经过多年发展,已经总结出一些基本的软件设计概念与原则,这些概念与原则经过时间的考验成为软件设计人员完成复杂的软件设计问题的基础。主要内容包括有:

(1)将软件划分成若干独立成分的依据。

(2)怎样表示不同的成分内的功能细节和数据结构。 (3)怎样统一衡量软件设计的技术质量。 4.2.1 模块化

模块是数据说明、可执行语句等程序对象的集合,可以对模块单独命名,而且可通过名字访问,例如,过程、函数、子程序、宏等等都可作为模块。模块化就是把程序划分成若干个模块,每个模块具有一个确定的子功能,把这些模块集成一个整体,可以完成指定的功能。

在软件开发过程中,大型软件由于其控制路径多、涉及范围广且变量数目多使其总体结构更为复杂,这样与小型软件相比较其可理解性和可阅读性较差。模块化增强了对复杂的大型程序的可理解性与可管理性。下面定量地描述模块化的根据。

4

定义函数C(x)为问题x的复杂程度,函数E(x)为解决间题x需要的工作量(时间)。对于问题P 1 和问题P 2 ,如

C(P 1 )>C(P 2 ), 则有E(P 1 )>E(P 2 ) 因为由P 1 和P 2 两个问题组合而成一个问题的复杂程度大于分别考虑每个问题时的复杂程度之和。C(P 1 +P 2 )>C(P 1 )+C(P 2 )综上所述,可得到下面的不等式:

E(P 1 +P 2 )>E(P 1 )+E(P 2 )

由此可知,把复杂的问题分解成许多容易解决的较小问题,原来的问题也就容易解决了,这就是模块化提出的根据。

参阅图4-2,如果无限地分割软件,最后为了开发软件而需要的工作量也就小得可以忽略了。事实上,当模块数目增加时,每个模块的规模将减小,虽然开发单个模块需要的工作量减少了,但是随着模块数目增加,设计模块间接口所需要的工作量将增加。折衷考虑这两个因素,可得出了图中所示的总成本曲线。每个程序都相应地有一个最适当的模块数目M,使得系统的开发工作量为最小。

图4-2 模块数目与工作量关系

虽然目前还不能精确地决定M的数值,但是在考虑模块化的时候模块数目与工作量关系曲线是有用的指南。

采用模块化原理可以使软件结构清晰,不仅容易实现设计,也使设计出的软件的可阅读性和可理解性大大增强。这是由于程序错误通常发生在有关的模块及它们之间的接口中,所以采用了模块化技术会使软件容易测试和调试,进而有助于提高软件的可靠性。因为变动往往只涉及少数几个模块,所以模块化能够提高软件的可修改性。模块化也有助于软件开发工程的组织管理,一个复杂的大型程序可以由许多程序员分工编写不同的模块。 4.2.2 抽象与逐步求精

5

在现实世界中,事物、状态或过程之间存在共性。把这些共性集中和概括起来,忽略它们之间的差异,这就是抽象。抽象就是抽出事物的本质特性而暂时不考虑它们的细节。

处理复杂系统的有效的方法是用层次的方式构造和分析它。一个复杂的动态系统首先可以用一些高级的抽象概念构造和理解,这些高级概念又可以用一些较低级的概念构造和理解,如此进行下去,直至最低层次的具体元素。这种层次的思维和解题方式必须反映在定义动态系统的程序结构之中,每级的一个概念将以某种方式对应于程序的一组成分。

当考虑对任何问题的模块化解法时,可以提出许多抽象的层次。在抽象的最高层次使用问题环境的语言,以概括的方式叙述问题的解法;在较低抽象层次采用更过程化的方法,把面向问题的术语和面向实现的术语结合起来叙述问题的解法;最后,在最低的抽象层次用可以直接实现的方式叙述问题的解法。

软件工程过程的每一步都是对软件解法的抽象层次的一次精化。在可行性研究阶段,软件作为系统的一个完整部件;在需求分析期间,软件解法是使用在问题环境内熟悉的方式描述的;当我们由总体设计向详细设计过渡时,抽象的程度也就随之减少了;最后,当源程序写出来以后,也就达到了抽象的最低层。

逐步求精与抽象是紧密相关,随着软件开发工程的进展,在软件结构每一层中的模块,表示了对软件抽象层次的一次精化。层次结构的上一层是下一层的抽象,下一层是上一层的求精。事实上,软件结构顶层的模块,控制了系统的主要功能并且影响全局;在软件结构底层的模块,完成对数据的一个具体处理,用自项向下由抽象到具体的方式分配控制,简化了软件的设计和实现,提高了软件的可理解性和可测试性,并且使软件更容易维护。

例: 开发一个 CAD软件,能够实现绘图系统的全部功能,供低级CAD使用。 抽象层次 1 用问题所处环境的术语描述这个软件

该软件系统具有与可视化通信的图形界面,能用鼠标代替绘图工具划出各种曲线和直线。能完成几何计算和截面视图及辅助视图的设计,图形设计结果存于图形文件中。

抽象层次 2 所用术语不再是问题所处环境的语言,但并没给出怎样做的信息,不能直接实现。 CAD 软件任务 用户界面任务; 创建二维图形任务;

显示图形任务;管理图形任务; end CAD

抽象层次 3 仅以二维图形任务为例

6

PROCEDURE 创建二维图形 REPEAT UNTIL 创建图形任务终止 DO WHILE 出现与数字仪的交互时 数字仪接口任务; 判断作图请求; 线:画线任务; 圆:画圆任务; . END;

DO WHILE 出现与键盘的交互时 键盘接口任务; 选择分析或计算; 辅助视图:辅助视图任务; 截面视图:截面视图任务; . END .

END PROCEDURE.

在这一抽象层次上,给出了初步过程表示,模块结构已清楚明朗,求精过程还可进行下去,直到得到源代码。 4.2.3 信息隐蔽和局部化

应用模块化原理时,将产生的一个问题:为了得到一组模块,应该如何分解软件结构。信息隐蔽原理指出:每一个模块的实现细节对于其他模块来说是隐蔽的,也就是说,模块中所包括的信息不允许其它不需要这些信息的模块调用。隐蔽表明有效的模块化可以通过定义一组独立的模块而实现,这些独立的模块间仅交换为完成系统功能而必须交换的信息。

模块间的通信仅使用对于实现软件功能的必要信息,通过抽象,可以确定组成软件的过程实体;而通过信息隐蔽,则可以定义和实施对模块的过程细节和局部数据结构的存取限制。局部化的概念和信息隐蔽概念密切相关。局部化是指把一些关系密切的软件元素物理地放得彼此靠近。在模块中使用局部数据元素就是局部化的一个例子。显然,局部化有助于实现信息隐蔽。

7

如果在测试期间和以后的软件维护期间需要修改软件,那么使用信息隐蔽原理作为模块化系统设计的标准就会带来极大好处。因为绝大多数数据和过程对于软件的其他部分而言是隐蔽的,也就是看不见的,在修改期间由于疏忽而引入的错误传播到软件的其他部分的机会就很少。 4.2.4 模块独立性

模块独立性是指软件系统中的每个模块只具有软件要求的具体子功能,而与软件系统中其他的模块接口是简单的。例如,如果一个模块只具有单一的功能,并且与其他的模块没有太多的联系,那末称此模块具有模块独立性。 模块独立性的概念体现了模块化、抽象、信息隐蔽和局部化概念。开发具有独立功能而且和其他模块之间没有过多的相互作用的模块,就可以做到模块独立。换句话说,希望这样设计软件结构,使得每个模块完成一个相对独立的特定子功能,并且与其他模块之间的关系很简单。

模块的独立程度可以由内聚和耦合两个标准来度量。耦合表示不同模块间互相连接的紧密程度;内聚表示一个模块内部各个元素彼此结合的紧密程度。 1.耦合

耦合是对一个软件结构内各个模块之间互连程度的度量。耦合强弱取决于模块间接口的复杂程度,调用模块的方式,以及通过接口的信息。 在软件设计中应该尽可能采用松散耦合。在松散耦合的系统中测试或维护任何一个模块,而不影响系统的其他模块。由于模块间联系简单,在一处发生错误就很小有可能性传播到整个系统。因此,模块间的耦合程度影响系统的可理解性、可测试性、可靠性和可维护性。 具体区分模块间耦合程度的标准如下。 ( 1) 非直接耦合

如果两个模块中的每一个都能独立地工作而不需要另一个模块的存在,那么它们彼此完全独立,这表明两个模块间无任何连接,耦合程度最低。但是,在一个软件系统中不可能所有模块之间都没有任何连接,因为模块之间的联系是通过模块的控制和调用来实现的。 ( 2)数据耦合

如果两个模块彼此间通过参数交换信息,而且交换的信息仅仅是数据,那么这种耦合称为数据耦合。数据耦合是低耦合。系统中至少必须存在这种耦合,因为只有当某些模块的输出数据作为另一些模块的输入数据时,系统才能完成有价值的功能。一般说来,一个系统内可以只含有数据耦合。 ( 3)控制耦合

如果在模块间传递的信息中含有控制信息(有时控制信息以数据的形式出现),则这种耦合称为控制耦合,如图 4-3所示。控制耦合是中等程度的耦

8

合,它增加了系统的复杂程度。在把模块分解之后通常可以用数据耦合代替控制耦合。

图 4-3控制耦合

( 4)公共环境耦合

当两个或多个模块通过一个公共数据环境相互作用时,这种耦合称为公共环境耦合。这里的公共环境可以是全程变量、共享的通信区、内存的公共覆盖区、任何存储介质上的文件、物理设备等等。

① 公共环境耦合的复杂程度随耦合的模块个数而变化,当耦合的模块个数增加时复杂程度显著增加。如果只有两个模块有公共环境,那么这种耦合有下述两种可能,(参阅图 4-4)。

② 一个模块往公共环境送数据,另一个模块从公共环境取数据。这是数据耦合的一种形式,是比较松散的耦合。

两个模块都既往公共环境送数据又从里面取数据,这种耦合比较紧密,介于数据耦合和控制耦合之间。如果两个模块共享的数据很多,通过参数传递可能很不方便,这时可以利用公共环境耦合。

图4-4公共环境耦合

9

图4-5 内容耦合

( 5)内容耦合

最高程度的耦合是内容耦合。如果出现下列情况之一(参阅图 4-5),两个模块间就发生了内容耦合:

① 一个模块访问另一个模块的内部数据;

② 一个模块不通过正常人口而转到另一个模块的内部;

③ 两个模块有一部分程序代码重叠(只可能出现在汇编程序中); ④ 一个模块有多个人口(这表明一个模块有几种功能)。

应该避免使用内容耦合。事实上许多高级程序设计语言已经设计成不允许在程序中出现任何形式的内容耦合。 ( 6)标记耦合

如果一组模块通过参数表传递记录信息,也就是说,这组模块共享了这个记录,就是标记耦合。在设计中避免标记耦合。 ( 7)外部耦合

一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该变量的信息,则称之为外部耦合。

模块之间的耦合一般分为七种类型,如图 4-6所示。总之,耦合是影响软件复杂程度的一个重要因素。应该采取的原则是:尽量使用数据耦合,少用控制耦合,限制公共环境耦合的范围,完全不用内容耦合。

图 4-6七种耦合类型的关系

10

图 4-7偶然内聚

2.内聚

内聚表示一个模块内各个元素间结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。简单地说,理想内聚的模块只做完成一个子功能。 设计时应该力求做到高内聚,通常中等程度的内聚也是可以采用的,而且效果和高内聚相差不多;但是,低内聚不要使用。

内聚和耦合是密切相关的,模块内的高内聚往往意味着模块间的松耦合。内聚和耦合都是进行模块化设计的有力工具,但是实践表明内聚更重要,应该把更多注意力集中到提高模块的内聚程度上。 (1)偶然内聚

如果一个模块完成一组任务,这些任务间的关系很松散,这就称为偶然内聚,参阅图 4-7。例如在写完某一个程序之后,发现一些语句在两处或多处出现,于是把这些语句作为一个模块,这样模块为偶然内聚的模块。 ( 2)逻辑内聚

如果一个模块完成的功能在逻辑上属于相同或相似的一类,则称为逻辑内聚。例如,一个模块的功能是产生各种类型的全部输出,参阅图 4-8。

11

图 4-8逻辑内聚

图 4-9通信内聚模块

( 3)时间内聚

如果一个模块包含的任务必须在同一段时间内执行,就叫时间内聚。例如,模块完成各种初始化工作。

在偶然内聚的模块中.各种元素之间没有实质性联系,很可能在一种应用场合需要修改这个模块,在另一种应用场合又不允许这种修改,从而陷入困境。事实上,偶然内聚的模块出现修改错误的概率比其他类型的模块高得多。

12

在逻辑内聚的模块中,不同功能混在一起,合用部分程序代码,即使局部功能的修改有时也会影响全局。因此,这类模块的修改也比较困难。 时间关系在一定程度上反映了程序的某些实质,所以时间内聚比逻辑内聚好一些。

( 4)过程内聚

如果一个模块内的处理元素是相关的,而且必须以特定次序执行,则称为过程内聚。使用程序流程图作为工具设计软件时,常常通过研究流程图确定模块的划分,这样得到的往往是过程内聚的模块。 ( 5)通信内聚

如果模块中所有元素都使用同一个输入数据和(或)产生同一个输出数据,则称为通信内聚。图 4-9所示的是通信内聚模块的示意图。 ( 6)信息内聚

信息内聚模块能完成多种功能,各个功能都在同一数据结构上操作,每一项功能有一个唯一的入口点,例如图 4-10所示的模块有4个功能,即这个模块将根据要求,确定该执行哪一个功能。但这个模块都基于同一数据结构,即符号表。

图 4-10信息内聚

图 4-11内聚的七种类型

( 7)功能内聚

13

如果模块内所有处理元素属于一个整体,完成一个单一的功能,则称为功能内聚。功能内聚是最高程度的内聚。 内聚的七种类型的级别比较如图 4-11所示。

重要的是设计时力争做到高内聚,并且能够辨认出低内聚的模块,通过修改设计提高模块的内聚程度,并降低模块间的耦合程度,从而获得较高的模块独立性。

4.2.5 结构设计原则

软件总体设计包括模块构成的程序结构和输入输出数据结构。其目标是产生一个模块化的程序结构,并明确模块间的控制关系,以及定义界面、说明程序的数据,进一步调整程序结构和数据结构。软件设计从需求分析开始,逐步分层的导出程序结构和数据结构,如图4-12所示。

图 4-12结构变化

14

图 4-13对同一问题的多种软件结构

同一问题可有多个解,如图 4-13所示。提高模块的内聚程度降低模块间的耦合程度是一个评价的标准。

改进软件设计、提高软件质量的原则如下。 1.模块高独立性

设计出软件的初步结构以后,应该进一步分解或合并模块,力求降低耦合提高内聚。例如,多个模块公有的一个子功能可以独立定义一个模块,由这些模块调用;有时可以通过分解或合并模块以减少控制信息的传递及对全程数据的引用,并降低接口的复杂程度。 2.模块规模适中

. 一个模块的规模不应过大,最好能写在一页纸内。从心理学角度研究得知,当一个模块包含的语句数超过30以后,模块的可理解程度迅速下降。 ? 大的模块往往是由于分解不充分,但是进一步分解必须符合问题结构,一般说来,分解后不应该降低模块独立性。

? 过小的模块开销大于有效操作,而且模块数目过多将使系统接口复杂。因此过小的模块有时不值得单独存在,特别是只有一个模块调用它时,通常可以把它合并到上级模块中去而不必单独存在。 3.深度、宽度、扇出和扇入适当

( 1)深度表示软件结构中控制的层数,能够粗略地标志一个系统的大小和复杂程度(参阅图4-14)。它和程序长度之间应该有粗略的对应关系,当然这个对应关系是在一定范围内变化的。如果层数过多,则应该考虑是否有许多管理模块过于简单,需要适当合并。

( 2)宽度是软件结构内同一个层次上的模块总数的最大值。一般说来,宽度越大系统越复杂。对宽度影响最大的因素是模块的扇出。

15

图 4-14程序结构的有关术语

( 3)扇出是一个模块直接调用的模块数目,扇出过大意味着模块过分复杂,需要控制和协调过多的下级模块;扇出过小也不好。经验表明,一个设计得好的典型系统的平均扇出通常是3或4。

( 4)扇出太大一般是因为缺乏中间层次,应该适当增加中间层次的控制模块。扇出太小时可以把下级模块进一步分解成若干个子功能模块,或者合并到它的上级模块中去。当然分解模块或合并模块必须符合问题结构,不能违背模块独立原理。

( 5)一个模块的扇入表明有多少个上级模块直接调用它,扇入越大则共享该模块的上级模块数目越多,这是有好处的,但是,不能违背模块独立单纯追求高扇入。

( 6)观察大量软件系统后发现,设计得优秀的软件结构通常顶层扇出比较高,中层扇出较少,底层扇入到公共的实用模块中去。 ? 模块的作用域应该在其控制域之内

16

图4-15 模块的作用域和控制域

模块的作用域定义为受该模块判定影响的所有模块的集合。模块的控制城是这个模块本身以及所有直接或间接从属于它的模块的集合。例如,在图 4-15中模块A的控制域是A、B、C、D、E、F等模块的集合。

在一个设计得很好的软件系统中,所有受判定影响的模块应该都从属于做出判定的那个模块,最好局限于做出判定的那个模块本身及它的直属下级模块。例如,如果图 4-15中模块A做出的判定只影响模块B,那么是符合这条规则的。但是,如果模块A做出的判定同时还 影响模块 G中的处理过程,这样的结构使得软件难于理解。其次,为了使得A中的判定能影响G中的处理过程,通常需要在A中给一个标记设置状态以指示判定的结果,并且应该把这个标记传递给A和G的公共上级模块M,再由M把它传给G。这个标记是控制信息而不是数据,因此将使模块间出现控制耦合。

可以通过修改软件结构能使作用域是控制域的子集,一个方法是把做判定的点往上移,例如,把判定从模块 A中移到模块M中、另一个方法是把那些在作用域内但不在控制域内的模块移到控制域内,例如,把模块G移到模块A的下面,成为它的直属下级模块。 5.模块接口的低复杂度

模块接口复杂是软件发生错误的主要原因之一。应该设计模块接口使得信息传递简单并且和模块的功能一致。

例如,一元二次方程的根的模块QUAD-ROOT(TBL,X),其中用数组TBI。传送方程的系数,用数组X回送求得的根。这种传递信息的方法不利于对这个模块的理解,不仅在维护期间容易引起混淆,在开发期间也可能发生错误。下面这种接口可能是比较简单的。

QUAD_ROOT(A,B,C,ROOTI,ROOT2)其中A、B、C是方程的系数,ROOTI和 ROOTZ是算出的两个根。

接口复杂或者不一致是紧耦合或低内聚的原因所致,应该重新分析这个模块的独立性,力争降低模块接口的复杂程度。 6.单入口单出口的模块

这条启发式规则表明不要使模块间出现内容耦合。在结构上模块顶部有单入口,模块底部单出口,这样的结构比较容易理解、比较容易维护。

17

7.模块功能应可预测

模块的功能应能预测,如果一个模块可以当做一个黑盒子,只要输入的数据相同就产生同样的输出,这个模块的功能就是可以预测的。带有内部存储器的模块的功能可能是不可预测的,因为它的输出可能取决于内部存储器(例如某个标记)的状态。由于内部存储器对于上级模块而言是不可见的,所以这样的模块不易理解、难于测试和维护。

如果一个模块只完成一个单独的子功能,则表现高内聚;但是,如果一个模块任意限制局部数据结构的大小,过分限制在控制流中可以做出的选择或者外部接口的模式,那么这种模块的功能就过分局限,使用范围也就过于狭窄。在使用过程中将不可避免地需要修改功能过分局限的模块,以提高模块的灵活性,扩大它的使用范围;但是,在使用现场修改软件的代价是很高的。 4.3 面向数据流的设计方法

在这一节,将介绍一种应用最广、技术上也较完善的系统设计方法,面向数据流的设计方法。面向数据流的设计方法的目标是给出设计软件结构的一个系统化途径。

结构化设计方法属于面向数据流的设计方法。在需求分析阶段,首先要考虑的一个关键问题就是信息流。信息流是软件开发人员考虑问题的出发点和基础。信息流从系统的输入端向输出端流动,要经历一系列的变换或处理。用来表现这个过程的数据流图( DFD)就是软件系统的逻辑模型。面向数据流的设计要解决的任务,就是在上述需求分析的基础上,将DFD图映射为软件系统的结构。换句话说,这类设计方法允许把用DFD图表示的系统逻辑模型方便地转换成对于软件结构的初始设计描述。在结构化设计方法中,软件的结构将用系统结构图来描述。

为了有效地实现从 DFD图到系统结构图的映射,结构化设计(SD)方法的步骤如下:

S1:复审DFD图,必要时可再次进行修改或细化;

S2:鉴别DFD图所表示的软件系统的结构特征,确定它所代表的软件结构是属于变换型还是事务型;

S3:按照SD方法规定的一组规则,把DFD图映射为初始的系统结构图; S4:按照设计改进原则细化和改进初始的系统结构图,获得最终系统结构图。 4.3.1 基本概念

以面向数据流的设计方法把信息流映射成软件结构,信息流的类型决定了映射的方法,信息流有下述两种类型。 (1)变换流

18

根据基本系统模型,信息通常以外部世界的形式进入软件系统,经过处理以后再以外部世界的形式离开系统。

如图4-16所示,信息沿输入通路进入系统,同时由外部形式变换成内部形式,进入系统的信息通过变换中心,经加工处理以后再沿输出通路变换成外部形式离开软件系统。当信息流具有这些特征时,称为变换流。

图4-16 变换流

(2)事务流

原则上所有信息流都可以归结为变换流类。但是,当信息流具有和图 4-17类似的形状时,称信息流是以事务为中心,也就是说,数据沿输入通路到达一个处理T,这个处理根据输入数据的类型在若干个动作序列中选出一个来执行。这类系统的特征能具有在多种事务中选择执行某类事务的能力。事务型结构至少有一条接受路径,一个事务中心,与若干条动作路径组成。这类信息流应该划为一类特殊的信息流,称为事务流。图4-17 中的处理T称为事务中心,它完成下述任务:

1)接收输入事务(事务又称为输入数据); 2)分析每个事务以确定它的类型; 3)根据事务类型选取一条活动通路。

图4-17 事务流

19

基于面向数据流方法的设计过程如图4-18所示。

图4-18 面向数据流方法设计过程

4.3.2 系统结构图的组成

系统结构图是SD方法在总体设计中使用的主要表达工具,用来显示软件的组成模块及其调用关系。SD方法约定,用矩形框来表示模块,用带箭头的连线表示模块间的调用关系。在调用线的两旁,应标出传入和传出模块的数据流。 (l)系统结构模块的表示符号

图4-19 系统结构图的六种模块

20

不能再分解的底层模块称为原子模块。如果一个系统的全部实际加工由原子模块来完成,而其它非原子模块只是执行控制和协调工作,那么这种系统就称为完全因子分解的系统。图 4-19显示了系统结构图允许使用的6种模块。 其中传入、传出和变换模块用来组成变换结构中的各个相应郎分。源模块是不调用其它模块的传入模块,只用于传入部分的始端。漏模块是不调用其它模块的传出模块,仅用于传出部分的末端。控制模块是只调用其它模块、而不被其它模块调用的模块,例如变换型结构的顶层模块,事务型结构的事务中心等,均属于控制模块这一类。 (2)简单调用

图4-20 模块的简单调用

在系统结构图中,调用线的箭头指向被调用模块。见图 4-20,在图4-20(a)中,允许模块A调用模块B和模块C,而不是相反。调用B时,A向它传送数据流X与Y,B向A返回数据流动调用C时,A仅向C传送数据流动。显而易见,B属于变换模块,C属于漏模块。图4-20(b)是图(a)的一种替代画法。用附表列出在模块间传送的数据流,以代替直接在调用线的两侧作标注。当系统结构图包含的数据流太多时,将造成画面拥挤,采用这种画法可使画面简洁并能减少错误。 (3)选择调用

图4-21 模块的选择调用

选择调用的画法如图 4-21所示。图中用菱形符号来表示选择。左方菱形的含义是:模块A根据它内部的判断,来决定要不要调用模块B。右方的菱形则表示A按照另一判定的结果,选择调用模块C或者模块D。

21

图4-22 模块的循环调用

(4)循环调用

用叠加在调用线始端的环形箭头表示循环。图 4-22 的含义是:模块A将根据其内在的循环重复调用B、C等模块,直至在A模块内部出现满足循环终止的条件为止。 以上简述了系统结构图的符号和画法。利用这些画法,可以将目标系统的DFD图转换为目标系统的初始系统结构图。

SD方法提出了两种分析与过渡方法:即变换分析与事务分析方法。利用它们能方便地把 DFD图转换为初始系统结构图。前者适用于 DFD图中的变换型结构,后者适用于DFD图中的事务型结构。图4-23简明的说明了变换分析与事务分析各自的功能。

图4-23 变换分析与事务分析的功能

4.3.3 变换分析

经过变换分析步骤把具有变换流特点的数据流图按预先确定的模式映射成软件结构图。

1.对DFD图的分析和划分

首先区分传入、传出和变换中心三个部分,在 DFD图上标明它们的分界线。 前已说明,变换结构由传入、传出和变换中心三部分组成。变换中心的任务,就是通过计算或者处理,把系统的逻辑输人变换(或加工)为系统的逻辑输出。所谓逻辑输入,是指离物理输入端(输入始端)最远,但仍可以被看作系统输入的那些数据流。而逻辑输出则是指离物理输出端(输出末端)最远,但仍可视为系统输出的所有数据流。需要指出,当数据在系统中流动时,不仅在通过变换中心时要被变换,在传入和传出的路径上,其内容和形式也可能发生变化。所以有时把变换中心称为中心加工,以区别干数据在传入传出过程中常见的其它加工。

22

图4-24 变换型分析

图 4-24 是在DFD上区分三个组成部分的一个例子。图中c、e是逻辑输入数据流,u、w是逻辑输出数据流,介于它们之间的P,Q,R属于中心加工。用虚线表示的两条分界线,标出了这三个部分的边界。

对DFD图的分析和划分是变换分析的第一步。对于较复杂的DFD图,可以有多种的不同划分结果。以下列出几种可能遇到的情况及其处理方法。 ·有些系统没有加工中心,系统的逻辑输入和逻辑输出是相同的数据流。此时应如实地把 DFD图划分为传入和传出两个部分,不要强求分成三个部分。 ·除传入部分外,在变换中心甚至传出部分也可能从系统外接受某些输入数据流,称为二次输入数据。分析时,应把二次输人数据看成变换中心或输出部分的一个成份,不应当作输入部分的一部分。

·有些 DFD图可能太粗,缺少应有的细节。遇到这种情况,设计人员可对作为分析的DFD图进行补充,必要时甚至重画。过多的细节有益后面的设计。 2.完成第一级分解

这一步要画出初始的系统结构图,主要是画出它最上面的两层模块,即顶层模块和第一层模块。任何系统的顶层都只有一个用于控制的主模块。它的下一层(第一层)一般包括输入、输出和中心变换三个模块,分别代表系统的三个相应分支。但也可能只有输入和输出两个模块,可据DFD图的实际划分情况而定。

图 4-25 显示了图4-24的DFD图在第一级分解后导出的系统结构图,沿调用线标注了在模块间输送的数据流的名称。

23

图4-25 第一层DFD图

另一种画法,在第一层不是每一分支只画一个模块,而是按照实际情况确定模块的数量。仍以图4-24为例,输入和输出分支各有两个数据流,而中心加工会有三个加工,故可画出(2+2+3)共7个模块,如图4-26 所示。由于初始系统结构图还要细化和优化,这两种画法的差异,对最终的系统结构图无关紧要。

图4-26 模块间的调用

3. 完成第二级分解

对上步的结果继续进行由顶向下的分解,直至画出每个分支所需要的全部模块,称为第二级分解。这一步得到的结果便是系统的初始系统结构图。 同第一级分解一样,这一步的分解实质上仍然是映射,即把 DFD图中的加工按照一定规则转换为系统结构图中的模块。这就使整个工作变得有章可循,这也是SD方法的一大优点。

仍以图 4-24 为例,首先考察输入分支的模块分解。在图4-27 中输入模块 M A 可直接调用模块C与E以取得它所需的数据流c与e继续下推,模块C、E将分别调用各自的下属模块B、D,以取得b与d。模块B又通过调用下属模块A取得数据a。可见图 4-27中的5个下属模块就是DFD图中从A至E这5个加工的映射,但模块的调用顺序正好与加工顺序相反。

24

图4-27 第二级分解

数据流在输入的过程中,也可能经历数据的变换。以图 4-27中的两个输入流为例,其中一路将从a变换为b,再变换为c;另一路则从d变换为e。为了表示出这种变换,可以在图中增添3个变换模块(即“变A为B”。“变B为C”、“变D为E”),并在模块A至E的名称中加上 Read、Get 等字样,如图 4-28所示。这一改变除了处于输入端的源模块以外,让每一输入模块都调用两个下属模块,包括一个下属的输入模块和一个变换模块。图4-28所显示的结构较图4-27更加清楚明了。

按图 4-28寻踪,考察一下输入分支的操作过程。为了取得数据c、e,M。将分别调用模块C和E。为了得到c(或e),首先要得到b(或d为了得到b又要先读入a。图4-29 显示了有关模块的调用与执行过程。虽然模块的调用顺序(CBA ,ED)恰与加工的出现顺序相反,但取得数据的顺序(abc,de) ,与 DFD的要求是一致的。

仿照与输入分支相似的分解方法,可得到本例中输出分支的两种模块分解图,如图 4-30所示。

与输入、输出分支相比,中心加工分支的情况繁简各异,其分解也较复杂。但建立初始的系统结构图时,仍可以采取“一对一映射”的简单转换方法。图4-31显示了本例中心加工分支第二级分解的结果。

将图4-28和 图4-30 (右边) 与图4-31合并在一起,就可以得到本例的初始系统结构图,如图4-32 所示。

图4-28 输入分支的第二种分解

25

选择结构的数据包含两个或多个数据元素,每次使用这个数据时按一定条件从这些数据元素中选择一个。图4-35就是用Jackson图表达选择结构的例子。 重复结构的数据,根据使用时的条件由一个数据元素出现零次或多次构成。 图 4-36所示的就是用Jackson图表达这种结构的一个例子。表示A由B重复N次实现。

图 4-36重复结构

(2) 改进的Jackson图

Jackson图的缺点是:用这种图形工具表示选择或重复结构时,选择条件或循环结束条件不能直接在图上表示出来,影响了图的表达能力,也不易直接把图翻译成程序,此外,框间连线为斜线,不易在行式打印机上输出。为了解决上述问题,允许将连线画成直线,并在连线一旁标注字母“S”(表示选择)或“I”(表示重复)及编号。

图 4-37所示的是改进的Jackson图。图4-37中(a)是顺序结构,B,C,D任一个都不能是选择出现或重复出现的数据元素,即不能是右上角有小圈或星号标记的元素;图4-37(b)是选择结构,s右面括号中的数字i是分支事件的编号; 图4-37 (C) 所示的是可选结构, A或者是元素b 或者不出现,可选结构是选择结构的一种常见的特殊形式;图4-37(d)所示的是重复结构,循环结束条件的编号为i。

31

图4-37 改进的Jackson图

Jackson图的优点:

? 便于表示层次结构,而且是对结构进行自顶向下分解的有力工具。 ? 形象直观,可读性好。

? 既能表示数据结构,也能表示程序结构。因为结构化程序设计也采用上述三种基本结构。 (3) Jackson图的使用 ① 表示数据结构

例1 :用Jackson图表示表4-38所示的二维表格。

32

图4-38 表示学生名册的二维表格

用 Jackson图表示学生名册的二维表格,首先声明该学生名册表格由表头和表体两部分组成 .其中表头又顺序包括表名和字段名。而表体可由任意行(0行或多行)组成,每行包括学生的姓名、性别、班级和学号。班级是本科的,学号项是本科生学号;班级是研究生的,学号项是研究生学号。

图 4-39用Jackson图来表示程序结构

② 表示程序结构

例 2: 用 Jackson图表示产生上面的学生名册文件的程序的程序结构 把图 4-39所表示的学生名册生成为一个计算机文件,则该程序结构可以用图4-40的Jackson图来表示。不难可以看出,这个图只是在图4-39的每个方框内的名称前添加“产生”二字。这种从数据结构图导出程序结构图的过程,称之为映射。

33

图4-40 用Jackson图表示程序结构

用Jackson图表示程序结构时,图中每个方框不一定都代表模块。大多数情况下,一个方框可能只是包含完成程序中一个简单操作的一条或几条语句。而且,在连接上、下层的连线表示包含(模块调用)。

③ Jackson伪代码,为了方便从程序结构到逻辑描述的转换,Jackson方法中为结构图设计了一组与之相对应的伪代码。Jackson方法中使用的伪代码和Jackson图是完全对应的,下面是和三种基本结构对应的伪代码。 与图4-34所示的顺序结构对应的伪码如下,其中‘seq'和‘end'是关键字: A seq b C D A end

其中‘ select ' 、‘ or',和‘end ' 是关键字 ,cond1、cond2和cond3分别是执行B、C或D的条件:与图4-35所示的选择结构对应的伪码如下: A select condI B

34

A or cond2 C

A or cond3 D A end

‘ iter‘,、‘until'、‘while'和 ‘ en d' 是关键字(重复结构有 until和while两种形式),cond是条件,与图4-36所示重复结构对应的伪码如下:

A iter until(或while) cond B A end

例: 在实际问题中,会遇到不同结构夹杂在一起的情况,如图 4-41所示。

图4-41 混合结构

. 有下述两种伪代码: (a): A seq B

C iter until cond I1 D end A

(b): A iter until cond1 B C D

35

end A

从图4-41中可以可以看出,执行A是要顺序执行B、C和D处理框,而C框要根据条件I1执行0次或多次。根据上述分析,显然在两种表示方法中图4-41是正确的。但是画法容易引起混淆,因此在遇到上面这种顺序结构中混杂有重复结构或选择结构时,应将结构图改画。图4-42就是一种改画方案。

4-42 改进画法

其相应的伪代码如下: A seq B

Cunit iter until cond I1 C

end Cunit D end A

2.Jackson方法步骤与实现 ( 1)Jackson方法的步骤

从Jackson方法与前面讨论的面向数据流的设计方法的比较如图4-43所示,可以看出两种方法有不同的出发点,一个出发点是数据结构,一个出发点是数据流。而且Jackson方法得到的程序过程性描述实际上已接近详细过程描述。

36

图4-43 Jackson方法与面向数据流设计方法比较

Jackson方法步骤如下:

前三步属于需求分析阶段,后四步属于设计阶段。

S1:从描述的问题中,提取软件系统要产生和运用的实体(人、物或组织),以及现实世界作用于实体的动作。

S2:把作用于实体的动作或由实体完成的动作,按时间发生的先后顺序构成进程。

S3:把实体模型与现实世界联系,模型系统的规格说明可以用系统规格说明图来表示。

S4:确定输入数据和输出数据的逻辑结构,并用Jackson图描绘这些数据结构。

S5:找出输入数据结构和输出数据结构中存在对应关系的数据单元。存在对应关系是指有直接的因果关系,在程序中可以同时处理的数据单元(对于重复出现的数据单元必须重复的次序和次数都相同才可能有对应关系)。从描绘数据结构的Jackson图导出描绘程序结构的Jackson图,规则如下: ①为每对在输入结构与输出结构中有对应关系的数据单元,按照它们在数据结构图中的层次在程序结构的相应层次画一个处理框,如果这对数据单元在输入数据结构和输出数据结构中所处的层次不同,则和它们对应的处理框在程序结构图中所处的层次与它们之中在数据结构图中层次低的那个对应; ②根据输入数据结构中剩余的每个数据单元所处的层次,在程序结构图的相应层次分别为它们画上对应的处理框;

③根据输出数据结构中剩余的每个数据单元所处的层次,在程序结构图的相应层次分别为它们画上对应的处理框;

37

④所有处理框在在程序结构图上的位置,应与由它处理的的数据单元在数据结构的Jackson图上的位置相对应。

描绘程序结构的Jackson图应该综合输入数据结构和输出数据结构的层次关系而导出来。在导出程序结构图的过程中,由于改进的Jackson图规定在构成顺序结构的元素中不能有重复出现或选择出现的元素,因此可能需要增加中间层次的处理框。做好这一步的关键是准确的找出有对应关系的所有数据单元。所谓对应单元,是指在程序中具有因果关系,可以或者需要放在一起处理的单元。

S6:列出完成结构图各框处理功能的全部操作和条件,如打开文件、关闭文件等辅助性操作,分支条件和循环结束条件等条件,并且把它们分配到程序结构图的适当位置。 S7:用伪码书写程序。 (2) Jackson方法的实现

Jackson方法的实现是基于数据结构导出程序或进程的结构方法。实现的本质就是:问题应当被分解为可以用三种基本结构(顺序、选择和重复)表示的部件的层次结构。,利用这三种基本结构可以组合成更复杂的结构体系,即过程构造。

例: 信用卡报帐系统。

某商店开展信用卡购物业务。建立了两个帐目付款帐目和用户总帐目。前者记录了每位用户每次付款的日期,金额,由用户的帐号,日期和交易金额组成。后者记录了用户存款余额。这两个帐目都是按用户的帐号进行登录的(见图4-44)。店方每隔一段时间都需要根据上述两个帐目产生一个会计报告。包括帐号、日期、交易金额、旧余额、新余额等内容,如图4-45所示。要求用Jackson方法设计一个能够产生上述会计报告的程序。 S1:画数据结构图

这个系统的两个输入文件是 付款帐目和用户总帐目。输出文件是会计报告。两个输入文件是以用户帐号组织记录的。输出数据结构的 Jackson图如图4-46所示。

会计报告中最后一行店方总计中由两项内容组成,即交易额总计和店方余额总计。报告其他部分是顾客数据。其输出数据结构的 Jackson图如图4-47所示。

38

图4-44 付款帐目和用户总帐目

图4-45 会计报告

图 4-46信用卡报帐系统的输入

39

图 4-47信用卡报帐系统的输出

S2:画程序结构图

从层次性输入和输出数据结构可以直接得到程序的过程性表示。在确定程序的结构时的规则如下:

? 对于每对有对应关系的数据单元,按照它们在输出数据结构中所在的层次,在程序结构的适当位置画一个数据框。

? 对于在每个输入数据结构中的数据单元,如果在输出数据结构中没有对应的数据单元,则为它在程序结构中的适当位置画一个程序框。

? 对于在每个输出数据结构中的数据单元,如果在输入数据结构中没有对应的数据单元,则为它在程序结构中的适当位置画一个程序框。

每产生一份会计报告,就须将付款帐目和用户总帐目分别打开一次。从图4-46和图4-47中可以看出三个数据结构图的第一层是相互对应的。在第二层中,图4-47中的用户帐号组和存款金额总计分别与图4-46中用户帐号组和用户记录两个单元相对应。再往下:图4-47的报告行与图4-46的付款记录相对应;图 4-47的旧存款余额与图4-46的存款余额相对应。由于输入数据结构中除去对应单元已无剩余单元,所以程序结构图可以直接由输出数据结构图(图4-47)映射得到,如图4-48所示。

40

本文来源:https://www.bwwdw.com/article/is56.html

Top