第三章软件设计 复习要求 1.了解软件概要设计的原则和过程。 2.掌握模块划分的评价准则一模块独立性的判别 3.掌握结构化设计方法 4.了解 Jackson系统开发方法和 Jackson程序设计方法。 5.了解数据设计和文件设计的原则。 6.掌握常用的详细设计的表达方法 6.了解软件设计规格说明和设计评审的主要内容 二、内容提要 1.软件设计的过程 旦软件需求确定之后,就进入开发阶段。开发阶段由三个互相关联的的步骤组成:设 计、实现(编码)和测试。每个步骤都按某种方式进行信息变换,最后得到有效的计算机软 件 (1)软件设计在开发阶段中的重要性 在软件需求分析阶段已经完全弄清楚了软件的各种需求,较好地解决了要让所开发的软 件“做什么”的问题,并已在软件需求规格说明和数据要求规格说明中详尽和充分地阐明了 这些需求。下一步就要着手实现软件的需求,即要着手解决“怎么做”的问题。 分析模型中的每一个成份都提供了建立设计模型所需的信息。软件设计的信息流如图4.1 所示。根据用数据、功能和行为模型表示的软件需求,采用某种设计方法进行数据设计、体 系结构设计、接口设计和过程设计。 据 实 象|关 据\格 过程设计 描系(数据词典)流说 接口设计 状态转换图 体系结构设计 控 说 数据设计 图41将分析模型转换为软件设计 数据设计将实体一关系图中描述的对象和关系,以及数据词典中描述的详细数据内容转
1 第三章 软件设计 一、复习要求 1. 了解软件概要设计的原则和过程。 2. 掌握模块划分的评价准则―模块独立性的判别。 3. 掌握结构化设计方法。 4. 了解 Jackson 系统开发方法和 Jackson 程序设计方法。 5. 了解数据设计和文件设计的原则。 6. 掌握常用的详细设计的表达方法。 6. 了解软件设计规格说明和设计评审的主要内容。 二、内容提要 1. 软件设计的过程 一旦软件需求确定之后,就进入开发阶段。开发阶段由三个互相关联的的步骤组成:设 计、实现(编码)和测试。每个步骤都按某种方式进行信息变换,最后得到有效的计算机软 件。 (1) 软件设计在开发阶段中的重要性 在软件需求分析阶段已经完全弄清楚了软件的各种需求,较好地解决了要让所开发的软 件“做什么”的问题,并已在软件需求规格说明和数据要求规格说明中详尽和充分地阐明了 这些需求。下一步就要着手实现软件的需求,即要着手解决“怎么做”的问题。 分析模型中的每一个成份都提供了建立设计模型所需的信息。软件设计的信息流如图4.1 所示。根据用数据、功能和行为模型表示的软件需求,采用某种设计方法进行数据设计、体 系结构设计、接口设计和过程设计。 图4.1 将分析模型转换为软件设计 数据设计将实体―关系图中描述的对象和关系,以及数据词典中描述的详细数据内容转 数据词典 数 据 流 图 实 体 关 系 图 状态转换图 加 工 控 制 规 规 格 格 说 说 明 明 数 据 对 象 描 述 过程设计 接口设计 体系结构设计 数据设计
化为数据结构的定义。体系结构设计定义软件系统各主要成份之间的关系。接口设计根据数 据流图定义软件内部各成份之间、软件与其它协同系统之间及软件与用户之间的交互机制。 过程设计则是把结构成份转换成软件的过程性描述。在编码步骤,根据这种过程性描述,生 成源程序代码,然后通过测试最终得到完整有效的软件。 软件设计是开发阶段中最重要的步骤,它是软件开发过程中质量得以保证的关键步骤。 设计提供了软件的表示,使得软件的质量评价成为可能。同时,软件设计又是将用户要求准 确地转化成为最终的软件产品的唯一途径。另一方面,软件设计是后续开发步骤及软件维护 工作的基础。如果没有设计,只能建立一个不稳定的系统,如图4.2所示。只要出现一些小小 的变动,就会使得软件垮掉,而且难于测试 维护 维护 测试 实现 设计 有软件设计 没有软件设计 图42软件设计的重要性 (2)软件设计的过程 软件设计是一个把软件需求变换成软件表示的过程。最初这种表示只是描绘出可直接反 映功能、数据、行为需求的软件的总的框架,然后进一步细化,在此框架中填入细节,把它 加工成在程序细节上非常接近于源程序的软件表示 从工程管理的角度来看,软件设计分两步完成。首先做概要设计,将软件需求转化为数 据结构和软件的系统结构,并建立接口。然后是详细设计,即过程设计。通过对结构表示进 行细化,得到软件的详细的数据结构和算法 McGlanghlin给出在将需求转换为设计时判断设计好坏的三条特征 设计必须实现分析模型中描述的所有显式需求,必须满足用户希望的所有隐式需求 设计必须是可读、可理解的,使得将来易于编程、易于测试、易于维护。 ■设计应从实现角度出发,给出与数据、功能、行为相关的软件全貌 以上三点就是软件设计过程的目标。为达到这些目标,必须建立衡量设计的技术标准。 ①设计出来的结构应是分层结构,从而建立软件成份之间的控制。 ②设计应当模块化,从逻辑上将软件划分为完成特定功能或子功能的构件。 ③设计应当既包含数据抽象,也包含过程抽象。 ④设计应当建立具有具有独立功能特征的模块。 ⑤设计应当建立能够降低模块与外部环境之间复杂连接的接口。 ⑥设计应能根据软件需求分析获取的信息,建立可驱动可重复的方法 软件设计过程根据基本的设计原则,使用系统化的方法和完全的的设计评审来建立良好 的设计 2.软件设计的原则 (1)抽象化
2 图 4.2 软件设计的重要性 化为数据结构的定义。体系结构设计定义软件系统各主要成份之间的关系。接口设计根据数 据流图定义软件内部各成份之间、软件与其它协同系统之间及软件与用户之间的交互机制。 过程设计则是把结构成份转换成软件的过程性描述。在编码步骤,根据这种过程性描述,生 成源程序代码,然后通过测试最终得到完整有效的软件。 软件设计是开发阶段中最重要的步骤,它是软件开发过程中质量得以保证的关键步骤。 设计提供了软件的表示,使得软件的质量评价成为可能。同时,软件设计又是将用户要求准 确地转化成为最终的软件产品的唯一途径。另一方面,软件设计是后续开发步骤及软件维护 工作的基础。如果没有设计,只能建立一个不稳定的系统,如图4.2所示。只要出现一些小小 的变动,就会使得软件垮掉,而且难于测试。 (2) 软件设计的过程 软件设计是一个把软件需求变换成软件表示的过程。最初这种表示只是描绘出可直接反 映功能、数据、行为需求的软件的总的框架,然后进一步细化,在此框架中填入细节,把它 加工成在程序细节上非常接近于源程序的软件表示。 从工程管理的角度来看,软件设计分两步完成。首先做概要设计,将软件需求转化为数 据结构和软件的系统结构,并建立接口。然后是详细设计,即过程设计。通过对结构表示进 行细化,得到软件的详细的数据结构和算法。 McGlanghlin 给出在将需求转换为设计时判断设计好坏的三条特征: ▪ 设计必须实现分析模型中描述的所有显式需求,必须满足用户希望的所有隐式需求。 ▪ 设计必须是可读、可理解的,使得将来易于编程、易于测试、易于维护。 ▪ 设计应从实现角度出发,给出与数据、功能、行为相关的软件全貌。 以上三点就是软件设计过程的目标。为达到这些目标,必须建立衡量设计的技术标准。 ① 设计出来的结构应是分层结构,从而建立软件成份之间的控制。 ② 设计应当模块化,从逻辑上将软件划分为完成特定功能或子功能的构件。 ③ 设计应当既包含数据抽象,也包含过程抽象。 ④ 设计应当建立具有具有独立功能特征的模块。 ⑤ 设计应当建立能够降低模块与外部环境之间复杂连接的接口。 ⑥ 设计应能根据软件需求分析获取的信息,建立可驱动可重复的方法。 软件设计过程根据基本的设计原则,使用系统化的方法和完全的的设计评审来建立良好 的设计。 2. 软件设计的原则 (1) 抽象化
对软件进行模块设计的时候,可以有不同的抽象层次。在最高的抽象层次上,可以使用 问题所处环境的语言描述问题的解法。而在较低的抽象层次上,则采用过程化的方法 过程的抽象:在软件工程过程中,从系统定义到实现,每进展一步都可以看做是对 软件解决方案的抽象化过程的一次细化。在软件计划阶段,软件被当做整个计算机系统中的 个元素来看待。在软件需求分析阶段,用“问题所处环境的为大家所熟悉的术语”来描述 软件的解决方法。而在从概要设计到详细设计的过程中,抽象化的层次逐次降低。当产生源 程序时到达最低的抽象层次 数据抽象:数据抽象与过程抽象一样,允许设计人员在不同层次上描述数据对象的 细节。例如,可以定义一个draw数据对象,并将它规定为一个抽象数据类型,用它的构成元 素来定义它的内部细节。此时,数据抽象draw本身是由另外一些数据抽象构成。而且在定义 draw的抽象数据类型之后,就可以引用它来定义其它数据对象,而不必涉及draw的内部细 节 ■控制抽象:与过程抽象和数据抽象一样,控制抽象可以包含一个程序控制机制而无 须规定其内部细节。控制抽象的例子就是在操作系统中用以协调某些活动的同步信号。 (2)自顶向下,逐步细化 Niklaus wirth提出的设计策略。将软件的体系结构按自顶向下方式,对各个层次的过程 细节和数据细节逐层细化,直到用程序设计语言的语句能够实现为止,从而最后确立整个的 体系结构。最初的说明只是概念性地描述了系统的功能或信息,但并未提供有关功能的内部 实现机制或有关信息的内部结构的任何信息。设计人员对初始说明仔细推敲,进行功能细化 或信息细化,给出实现的细节,划分出若干成份。然后再对这些成份,施行同样的细化工作。 随着细化工作的逐步展开,设计人员就能得到越来越多的细节 (3)模块化 软件系统的层次结构正是模块化的具体体现。就是说,整个软件被划分成若干单独命名 和可编址的部分,称之为模块。这些模块可以被组装起来以满足整个问题的需求 个大软件,由于其控制路径多、涉及范围广、变量多及其总体复杂性,使其相对于 个较小的软件不容易被人们理解。在解决问题的实践中,如果把两个问题结合起来作为一个 问题来处理,其理解复杂性大于这两个问题被分开考虑时的理解复杂性之和。因此,把一个 大而复杂的问题分解成一些独立的易于处理的小问题,解决起来就容易得多。 基于上述考虑,把问题/子问题(功能/子功能)的分解与软件开发中的系统/子系统 或者系统/模块对应起来,就能够把一个大而复杂的软件系统划分成易于理解的比较单纯的 模块结构。所谓“比较单纯”,是指模块和其它模块之间的接口应尽可能独立ε 实际上,如果模块是相互独立的,当模块变得越小,每个模块花费的工作量越低:但当 模块薮増加时,模块间的联系也随之増加,把这些模块联接起来的工作量也随之増加。如图 4.3所示。因此,存在一个模块个数M,它使得总的开发成本达到最小 成成本/模块 联接成本 总的软件成本 或工作量 最小成本范围 模块数目增加 模块大小减小 模块个数模块数/模块大小
3 对软件进行模块设计的时候,可以有不同的抽象层次。在最高的抽象层次上,可以使用 问题所处环境的语言描述问题的解法。而在较低的抽象层次上,则采用过程化的方法。 ▪ 过程的抽象 :在软件工程过程中,从系统定义到实现,每进展一步都可以看做是对 软件解决方案的抽象化过程的一次细化。在软件计划阶段,软件被当做整个计算机系统中的 一个元素来看待。在软件需求分析阶段,用“问题所处环境的为大家所熟悉的术语”来描述 软件的解决方法。而在从概要设计到详细设计的过程中,抽象化的层次逐次降低。当产生源 程序时到达最低的抽象层次。 ▪ 数据抽象 :数据抽象与过程抽象一样,允许设计人员在不同层次上描述数据对象的 细节。例如,可以定义一个 draw 数据对象,并将它规定为一个抽象数据类型,用它的构成元 素来定义它的内部细节。此时,数据抽象 draw 本身是由另外一些数据抽象构成。而且在定义 draw 的抽象数据类型之后,就可以引用它来定义其它数据对象,而不必涉及 draw 的内部细 节。 ▪ 控制抽象 :与过程抽象和数据抽象一样,控制抽象可以包含一个程序控制机制而无 须规定其内部细节。控制抽象的例子就是在操作系统中用以协调某些活动的同步信号。 (2) 自顶向下,逐步细化 Niklaus Wirth 提出的设计策略。将软件的体系结构按自顶向下方式,对各个层次的过程 细节和数据细节逐层细化,直到用程序设计语言的语句能够实现为止,从而最后确立整个的 体系结构。最初的说明只是概念性地描述了系统的功能或信息,但并未提供有关功能的内部 实现机制或有关信息的内部结构的任何信息。设计人员对初始说明仔细推敲,进行功能细化 或信息细化,给出实现的细节,划分出若干成份。然后再对这些成份,施行同样的细化工作。 随着细化工作的逐步展开,设计人员就能得到越来越多的细节。 (3) 模块化 软件系统的层次结构正是模块化的具体体现。就是说,整个软件被划分成若干单独命名 和可编址的部分,称之为模块。这些模块可以被组装起来以满足整个问题的需求。 一个大软件,由于其控制路径多、涉及范围广、变量多及其总体复杂性,使其相对于一 个较小的软件不容易被人们理解。在解决问题的实践中,如果把两个问题结合起来作为一个 问题来处理,其理解复杂性大于这两个问题被分开考虑时的理解复杂性之和。因此,把一个 大而复杂的问题分解成一些独立的易于处理的小问题,解决起来就容易得多。 基于上述考虑,把问题/子问题(功能/子功能)的分解与软件开发中的系统/子系统 或者系统/模块对应起来,就能够把一个大而复杂的软件系统划分成易于理解的比较单纯的 模块结构。所谓“比较单纯”,是指模块和其它模块之间的接口应尽可能独立。 实际上,如果模块是相互独立的,当模块变得越小,每个模块花费的工作量越低;但当 模块数增加时,模块间的联系也随之增加,把这些模块联接起来的工作量也随之增加。如图 4.3 所示。因此,存在一个模块个数 M, 它使得总的开发成本达到最小
图43模块大小、模块数目与费用的关系 (4)控制层次 控制层次也叫做程序结构,它表明了程序构件(模块)的组织情况。控制层次往往用程 序的层次(树形或网状)结构来表示。如图44所示。位于最上层根部是顶层模块,它是程 序的主模块。与其联系的有若干下属模块,各下属模块还可以进一步引出更下一层的下属模 块。模块M是顶层模块,如果算做第0层,则其下属模块A、B和C为第1层,模块D、E K、L和N是第2层,…,等等。 扇出 王 深 度 白面的面面∥ 扇入 宽度 图44程序的层次结构图示例 ·程序结构的深度:程序结构的层次数称为结构的深度。结构的深度在一定意义上反映 了程序结构的规模和复杂程度 程序结构的宽度:层次结构中同一层模块的最大模块个数称为结构的宽度 模块的扇入和扇出:扇出表示一个模块直接调用(或控制)的其它模块数目。扇入则 定义为调用(或控制)一个给定模块的模块个数。多扇出意味着需要控制和协调许多下属模 块。而多扇入的模块通常是公用模块 要注意的是,程序结构是软件的过程表示,但并未表明软件的某些过程性特征。比如, 进程序列、事件/决策的顺序或其它的软件动态特性 (5)结构划分 程序结构可以按水平方向或垂直方向进行划分。水平划分按主要的程序功能来定义模块 结构的各个分支。顶层模块是控制模块,用来协调程序各个功能之间的通信和运行。其下级 模块的最简单的水平划分方法是建立三个分支:输入、处理(数据变换)和输出。这种划分 的优点是:由于主要的功能相互分离,易于修改、易于扩充,且没有副作用。缺点是:需要 通过模块接口传递更多的数据,使程序流的整体控制复杂化 垂直划分也叫做因子划分。主要用在程序的体系结构中,且工作自顶向下逐层分布:顶 层模块执行控制功能,少做实际处理工作,而低层模块是实际输入、计算和输出的具体执行 者。这种划分的优点是:对低层模块的修改不太可能引起副作用的传播,而恰恰对计算机程 序的修改常常发生在低层的输入、计算或输出模块中。因此,程序的整体控制结构不太可能 被修改,便于将来的维护 (6)数据结构 数据结构是数据的各个元素之间的逻辑关系的一种表示。数据结构设计应确定数据的组 织、存取方式、相关程度、以及信息的不同处理方法。数据结构的组织方法和复杂程度可以
4 图 4.3 模块大小、模块数目与费用的关系 (4) 控制层次 控制层次也叫做程序结构,它表明了程序构件(模块)的组织情况。控制层次往往用程 序的层次(树形或网状)结构来表示。如图 4.4 所示。位于最上层根部是顶层模块,它是程 序的主模块。与其联系的有若干下属模块,各下属模块还可以进一步引出更下一层的下属模 块。模块 M 是顶层模块,如果算做第 0 层,则其下属模块 A、B 和 C 为第 1 层,模块 D、E、 K、L 和 N 是第 2 层,…,等等。 图 4.4 程序的层次结构图示例 ▪ 程序结构的深度:程序结构的层次数称为结构的深度。结构的深度在一定意义上反映 了程序结构的规模和复杂程度。 ▪ 程序结构的宽度:层次结构中同一层模块的最大模块个数称为结构的宽度。 ▪ 模块的扇入和扇出:扇出表示一个模块直接调用(或控制)的其它模块数目。扇入则 定义为调用(或控制)一个给定模块的模块个数。多扇出意味着需要控制和协调许多下属模 块。而多扇入的模块通常是公用模块。 要注意的是,程序结构是软件的过程表示,但并未表明软件的某些过程性特征。比如, 进程序列、事件∕决策的顺序或其它的软件动态特性。 (5) 结构划分 程序结构可以按水平方向或垂直方向进行划分。水平划分按主要的程序功能来定义模块 结构的各个分支。顶层模块是控制模块,用来协调程序各个功能之间的通信和运行。其下级 模块的最简单的水平划分方法是建立三个分支:输入、处理(数据变换)和输出。这种划分 的优点是:由于主要的功能相互分离,易于修改、易于扩充,且没有副作用。缺点是:需要 通过模块接口传递更多的数据,使程序流的整体控制复杂化。 垂直划分也叫做因子划分。主要用在程序的体系结构中,且工作自顶向下逐层分布:顶 层模块执行控制功能,少做实际处理工作,而低层模块是实际输入、计算和输出的具体执行 者。这种划分的优点是:对低层模块的修改不太可能引起副作用的传播,而恰恰对计算机程 序的修改常常发生在低层的输入、计算或输出模块中。因此,程序的整体控制结构不太可能 被修改,便于将来的维护。 (6) 数据结构 数据结构是数据的各个元素之间的逻辑关系的一种表示。数据结构设计应确定数据的组 织、存取方式、相关程度、以及信息的不同处理方法。数据结构的组织方法和复杂程度可以
灵活多样,但典型的数据结构种类是有限的,它们是构成一些更复杂结构的基本构件块。图 45表示了这些典型的数据结构。 标量项 链表 顺序向量 分层树 n维空间 图45典型的数据结构 标量是最简单的一种数据结构。所谓标量项就是单个的数据元素,例如一个布尔量、整 数、实数或一个字符串。可以通过名字对它们进行存取。 若把多个标量项组织成一个表或者顺序邻接为一组时,就形成了顺序向量。顺序向量又 称为一维数组。通常可以通过下标及数组名来访问数组中的某一元素。把顺序向量扩展到 维、三维,直至任意维,就形成了n维向量空间。最常见的n维向量空间是二维矩阵。 链表是一种更灵活的数据结构,它把不相邻的标量项、向量或空间结构用拉链指针链接 起来,使得它们可以像表一样得到处理。 组合上述基本数据结构可以构成其它数据结构。例如,可以用包含标量项、向量或n 维空间的多重链表来建立分层结构和网络结构。而利用它们又可以实现多种集合的存储 必须注意,数据结构和程序结构一样,可以在不同的抽象层次上表示。例如,一个栈是 种线性结构的逻辑模型,其特点是只允许在结构的一端进行插入或删除运算。它可以用向 量实现,也可以用链表实现。 (7)软件过程 模块A 模块A 图46一个模块内的软件过程 程序结构描述了整个程序的控制层次关系和各个部分的接口情况,而图46所示的软件
5 灵活多样,但典型的数据结构种类是有限的,它们是构成一些更复杂结构的基本构件块。图 4.5 表示了这些典型的数据结构。 图 4.5 典型的数据结构 标量是最简单的一种数据结构。所谓标量项就是单个的数据元素,例如一个布尔量、整 数、实数或一个字符串。可以通过名字对它们进行存取。 若把多个标量项组织成一个表或者顺序邻接为一组时,就形成了顺序向量。顺序向量又 称为一维数组。通常可以通过下标及数组名来访问数组中的某一元素。把顺序向量扩展到二 维、三维,直至任意维,就形成了 n 维向量空间。最常见的 n 维向量空间是二维矩阵。 链表是一种更灵活的数据结构,它把不相邻的标量项、向量或空间结构用拉链指针链接 起来,使得它们可以像表一样得到处理。 组合上述基本数据结构可以构成其它数据结构。例如,可以用包含标量项、向量或 n 维空间的多重链表来建立分层结构和网络结构。而利用它们又可以实现多种集合的存储。 必须注意,数据结构和程序结构一样,可以在不同的抽象层次上表示。例如,一个栈是 一种线性结构的逻辑模型,其特点是只允许在结构的一端进行插入或删除运算。它可以用向 量实现,也可以用链表实现。 (7) 软件过程 图 4.6 一个模块内的软件过程 程序结构描述了整个程序的控制层次关系和各个部分的接口情况,而图 4.6 所示的软件