软件工程导论-第四章 软件设计工程

本文详细介绍了软件设计过程,包括需求分析后的概要设计和详细设计阶段,强调了模块化、内聚和耦合的重要性,讨论了各种类型的内聚(如功能内聚、通信内聚等)和耦合(如数据耦合、控制耦合),并深入剖析了软件体系结构设计、风格和评审过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

软件设计工程概述

软件设计是做什么的

  • 经过需求分析阶段,项目开发者对系统的需求有了完整、准确、具体的理解和描述,知道了系统“做什么”,但是还不知道系统应该“怎么做”。软件设计的工作就是回答如何实现这些需求、系统应该“怎么做”的问题。
    在这里插入图片描述

  • 设计阶段:
    从工程管理的角度,可以将软件设计分为概要设计阶段和详细设计阶段。
    从技术的角度,传统的结构化方法将软件设计划分为体系结构设计、数据设计、接口设计和过程设计4部分。
    面向对象方法则将软件设计划分为体系结构设计、类设计/数据设计、接口设计和构件级设计4部分。
    在这里插入图片描述在这里插入图片描述

  • 软件设计过程
    软件设计是把软件需求变换成软件表示的过程
    软件设计是从软件需求规格说明书出发,根据需求分析阶段确定的功能设计软件系统的整体结构、划分功能模块、确定每个模块的实现算法以及编写具体的代码,形成软件的具体设计方案。

软件设计原则

功能独立

模块化

高内聚,低耦合
• 模块功能独立程度的两个定性标准度量:
• 内聚衡量一个模块内部各个元素彼此结合的紧密程度。内聚要高,每个模块完成一个相对独立的特定子功能。
• 耦合衡量不同模块彼此间互相依赖(连接)的紧密程度。耦合要低,即每个模块和其他模块之间的关系要简单;

内聚

一般模块的内聚性分为七种类型

在这里插入图片描述

(1) 巧合内聚(偶然内聚)

• 将几个模块中没有明确表现出独立功能的相同程序代码段独立出来建立的模块叫做巧合内聚(偶然内聚)。
• 例如:Word 2003版窗口的工具菜单,在本菜单中,各工具间基本没什么联系。该菜单具有巧合内聚(偶然内聚)。

(2) 逻辑内聚(logical cohesion)

• 如果一个模块完成的任务在逻辑上属于相同或相似的一类,则称为逻辑内聚。
在这里插入图片描述
• 例如:一个函数能打印季度开支报告、月份开支报告和日开支报告,具体打印哪一个,将由传入的控制标志决定,该函数具有逻辑内聚性
评价:
• 接口难以理解,造成整体上不易理解;
• 完成多个操作的代码互相纠缠在一起,即使局部功能的修改有时也会影响全局,导致严重的维护问题;
解决方案:
• 模块分解。 在这里插入图片描述

(3) 时间内聚(temporal cohesion)

• 如果一个模块包含的任务必须在同一段时间内执行,就叫时间内聚。
• 例如:操作系统的开机初始化模块,包含的动作没什么大的关系,但必须在开机后的一段时间内都完成。整个开机初始化模块具有时间内聚。
评价:
• 时间关系在一定程度上反映了程序某些实质,所以时间内聚比逻辑内聚好一些。
• 模块内操作之间的关系很弱,与其他模块的操作却有很强的关联。

(4) 过程内聚(procedural cohesion)

• 如果一个模块内的处理元素是相关的,而且必须以特定次序执行,则称为过程内聚。
• 使用程序流程图作为工具设计软件时,常常通过研究流程图确定模块的划分,这样得到的往往是过程内聚的模块。
在这里插入图片描述
• 例如:一个模块,为某员工计算工龄工资:打开员工信息文件取出员工记录;按一定的算法计算工龄;按一定的算法计算工龄工资。
• 该模块中的三个相对独立的子功能必须以特定次序执行,整个模块具有过程内聚。
评价:
• 比时间内聚好,至少操作之间是过程关联的。
• 仍是弱连接,不太可能重用模块。
解决方案:
• 分割为单独的模块,每个模块执行一个操作。

(5) 通信内聚(communicational cohesion)

• 如果模块中所有元素都使用同一个输入数据和(或)产生同一个输出数据,则称为通信内聚。即在同一个数据结构上操作。
在这里插入图片描述
• 假如有一个按给出的生日计算雇员年龄、退休时间的子程序,是根据同一个生日数据分别计算雇员年龄和退休时间,那么它就具有通信内聚。
在这里插入图片描述
评价:
• 模块中各操作紧密相连,比过程内聚更好
解决方案:
• 分成多个模块,每个模块执行一个操作。

(6) 顺序内聚(sequential cohesion)

• 如果一个模块内的处理元素和同一个功能密切相关,而且这些处理必须顺序执行,则称为顺序内聚。
评价:
• 根据数据流图划分模块时,通常得到顺序内聚的模块,这种模块彼此间的连接往往比较简单。
• 假如有一个按给出的生日计算雇员年龄、退休时间的子程序,如果它是利用所计算的年龄来确定雇员将要退休的时间,那么它就具有顺序内聚性。
在这里插入图片描述

(7) 功能内聚(functional cohesion)

• 如果模块内所有处理元素属于一个整体,完成一个单一的功能,则称为功能内聚。功能内聚是最高程度的内聚。
评价:
• 模块可重用,应尽可能重用;
• 可隔离错误,维护更容易;
• 扩充产品功能时更容易。
• 比如,计算雇员年龄的子程序就是功能内聚性的,因为它只完成一项工作,而且完成得很好;

int fac(int n)
{
	int f;
	if (n==0, n==1) f=1;
	else f=fac(n-1)*n;
	return(f);
}
/*函数fac,计算n!,本模块功能单一,具备功能内聚*/

七种内聚的优劣评分结果:

• 高内聚:功能内聚 10分
• 顺序内聚 9分
• 中内聚:通信内聚 7分
• 过程内聚 5分
• 低内聚:时间内聚 3分
• 逻辑内聚 1分
• 偶然内聚 0分
• 设计时力争做到高内聚,并且能够辨认出低内聚的模块。

耦合

• 耦合:是对一个软件结构内不同模块之间互连程度的度量,它取决于每个模块之间的接口的复杂程度,调用模块的方式。
• 要求:在软件设计中应该追求尽可能松散耦合的系统。

在这里插入图片描述
在这里插入图片描述

• 1) 内容耦合

如果一个模块直接访问另一个模块的内部数据;或者一个模块不通过正常入口转到另一模块内部;或者两个模块有一部分程序代码重迭;或者一个模块有多个入口,则两个模块之间就发生了内容耦合。
• 现代程序设计语言已经从语法上杜绝了内容耦合。

2) 公共耦合

若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。
• 例如:两个程序共享一个文件
在这里插入图片描述

3) 外部耦合

指模块间通过软件之外的环境联结(如I/O将模块耦合到特定的设备、格式、通信协议上)时,称为外部耦合。

#include <stdio.h>
int a, b;
void main( )
{
	pin( );
	b=a+1;
	prt( );
}
void pin( )
{
	printf ("print an integer number: ");
	scanf("%d", &a);
}
void prt( )
{
	printf("%d\n", b);
}
/*三个函数之间都存在外部耦合关系*/

4) 控制耦合

如果一个模块传送给另一个模块的参数中包含了控制信息,该控制信息用于控制接收模块中的执行逻辑,则称为控制耦合。

/* 根据输入的年龄是否满十八岁判断是否到达法定饮酒年龄*/
#include <stdio.h>
void main()
{
	int Age = 0; T=0;
	printf("%s","请输入您的年龄:");
	scanf("%d", &Age);
	if (age > 18)
	T = 1;
	else
	T = 0;
	YesOrNot(T);
}
void YesOrNot(int s)
{
	if (s == 1)
	printf("%s\n", "您已到达法定饮酒年龄!");
	else
	printf("%s\n","您未到达法定饮酒年龄!");
}
/*主函数main 和子函数YesOrNot 之间为控制耦合关系*/

5) 标记耦合

两个模块之间通过参数表传递一个数据结构的一部分(如某一数据结构的子结构),就是标记耦合。

#include <stdio.h>
void main( )
{
	int s, j, b[10];
	for (j=0; j<10; j++) 
		b[j]=j;
	s=sum(b[10]);
	printf("%d\n", s);
}
int sum(int a[10])
{
	int ss=0, i;
	for (i=0; i<10; i++) 	ss=ss+a[i];
	return(ss)
}
/*主函数main 和子函数sum 之间为标记耦合关系*/

5) 标记耦合

两个模块之间通过参数表传递一个数据结构的一部分(如某一数据结构的子结构),就是标记耦合。

#include <stdio.h>
void main( )
{
	int s, j, b[10];
	for (j=0; j<10; j++) 
		b[j]=j;
	s=sum(b[10]);
	printf("%d\n", s);
}
int sum(int a[10])
{
	int ss=0, i;
	for (i=0; i<10; i++) 	ss=ss+a[i];
	return(ss)
}
/*主函数main 和子函数sum 之间为标记耦合关系*/

6) 数据耦合

两个模块之间仅通过参数表传递简单数据,则称为数据耦合。

7) 非直接耦合

如果两个模块之间没有直接关系,即它们中的任何一个都不依赖于另一个而能独立工作,这种耦合称为非直接耦合。

#include <stdio.h>
void main( )
{
	int a, b;
	printf ("print an integer number: ");
	scanf("%d", &a);
	if (a<0) printf("data error! 	");
	else
	{
	b=fac(a);
	prt(b);
	}
}
int fac(int n)
{
	int f;
	if (n==0, n==1) f=1;
	else f=fac(n-1)*n;
	return(f);
}
void prt(int x)
{
	printf("%d\n", x);
}
/*上例中,主函数main 和子函数fac 之间为数据耦合关系,函数fac 和prt 之间为非直接耦合关系*/

使用耦合的原则

如果模块间必须存在耦合就尽量使用数据耦合少用控制耦合,限制公共耦合的范围坚决避免使用内容耦合

软件体系结构设计

体系结构发展过程

• 体系结构(architecture)一词在英文中就是“建筑”的意思。
• 如果把软件比作楼房,软件体系结构设计就如同设计楼房的类型(高层还是多层),电梯的位置,房间朝向等。
• 软件总有体系结构,不存在没有体系结构的软件。
• 体系结构并非是可运行的软件,是一种使设计师能够在更高层次分析“设计”是否满足需求的一种表示。

常见的软件体系结构

• 单主机结构:结构简单,客户界面、数据和程序都被集中在主机上,这种结构通常只支持一个用户操作,不需要考虑多个用户并发操作的问题。
• C/S(Client/Server)结构:应用程序的处理由客户机和服务器分担,处理请求通常被关系型数据库处理,客户机在接收到经过处理的数据后实现显示和业务逻辑,支持模块化开发,但是客户端程序在每个客户机是均需部署。
• B/S(Browser/Server)结构 :
在这里插入图片描述

软件体系结构的风格

1、数据为中心的体系结构

• 一些数据(比如一个文件或者数据库)保存在整个结构的中心,并且被其他部件频繁地使用、添加、删除、或者修改
在这里插入图片描述
在这里插入图片描述
例如:语言处理系统
• 自然语言处理系统把一种自然语言翻译成另一种自然语言。比如法语翻译成汉语。
• 编译器把人工的程序语言翻译成机器码。
• 其他语言处理系统把XML数据描述翻译成命令来查询数据库,或者翻译成替代XML的表示。
• 语言处理系统的数据为中心的体系结构
在这里插入图片描述

2、数据流风格的体系结构

• 这种结构适用于输入数据被一系列的计算或者处理部件变换成输出数据。
案例:ATM机系统。
在这里插入图片描述
在这里插入图片描述

3、调用和返回风格的体系结构

• 这种风格使一个软件设计者设计出非常容易修改和扩充的体系结构。
• 包含:主程序/子程序风格体系结构和远程过程调用风格的体系结构
在这里插入图片描述

在这里插入图片描述

4、面向对象的体系结构

• 系统部件封装数据和操作数据的方法。
• 部件之间的交互和协调通过消息来传递。
在这里插入图片描述

5、层次风格的体系结构

• 在这种结构中,定义不同的层次,每层都完成了相对外层更靠近机器指令的操作
在这里插入图片描述层次模型的典型应用—谷城网站的系统分层架构设计
在这里插入图片描述

在进行软件体系结构设计时,可以参考如下规则:

(1) 改进软件结构提高模块独立性
(2) 模块适当的深度、宽度、扇出和扇入
(3) 模块判断作用范围应在其控制作用范围内
(4) 力争降低模块接口的复杂度
(5) 设计单入口单出口的模块
(6) 模块功能应该是可以预测的模块大小适中
(7) 一般一个模块包含的语句在30~50条左右较好。
(8) 一个设计好的软件结构,通常顶层扇出比较高,中层扇出比较少,底层有高扇入。

部件级设计技术

• 在结构化分析和设计方法时部件往往被称为模块
• 在面向对象分析和设计时部件被称为类,
• 在基于构件的开发方法中,部件被称为构件

在部件级设计阶段,主要完成如下工作:

(1) 为每个部件确定采用的算法,选择某种适当的工具表达算法的过程,编写部件的详细过程性描述;
(2) 确定每一部件内部使用的数据结构;
(3) 在部件级设计结束时,应该把上述结果写入部件级设计说明书,并且通过复审形成正式文档,作为下一阶段(编码阶段)的工作依据。

部件级设计

• 详细描述处理过程常用三种工具:图形、表格和语言。
图形:程序流程图、N-S图、PAD图
表格:判定表
• 语言:过程设计语言(PDL)

*程序流程图

• 程序流程图独立于任何一种程序设计语言,比较直观、清晰、易于学习掌握
• 为使用流程图描述结构化程序,必须限制流程图只能使用五种基本控制结构
在这里插入图片描述
控制结构相互组合和嵌套的实例
在这里插入图片描述

*N-S图

• Nassi和Shneiderman 提出了一种符合结构化程序设计原则的图形描述工具,叫做盒图,也叫做N-S图
• 五种基本控制结构
在这里插入图片描述
控制结构相互组合和嵌套的实例
在这里插入图片描述

*PAD

• PAD是Problem Analysis Diagram的缩写 ,由程序流程图演化而来
• 五种基本控制结构
在这里插入图片描述
PAD实例
在这里插入图片描述

*判定表

• 当算法中包含多重嵌套的条件选择时,用程序流程图、N-S图或PAD都不易清楚地描述。
• 然而,判定表却能清晰地表达复杂的条件组合与应做动作之间的对应关系。
• 图4-11的例子 ,把多分支判断改为两分支判断

*设计性语言PDL

PDL(Program Design Language)是一种用于描述功能部件的算法设计和处理细节的语言,称为设计性语言
• 它是一种伪码。一般地,伪码的语法规则分为“外语法”和“内语法”
外语法应当符合一般程序设计语言常用语句的语法规则;
内语法可以用英语中一些简单的句子、短语和通用的数学符号,来描述程序应执行的功能

PDL特点
  1. 有固定的关键字外语法,提供全部结构化控制结构、数据说明和部件特征。属于外语法的关键字是有限的词汇集,它们能对PDL正文进行结构分割,使之变得易于理解。为了区别关键字,规定关键字一律大写,其它单词一律小写。
  2. 内语法使用自然语言来描述处理特性。内语法比较灵活,只要写清楚就可以,不必考虑语法错,以利于人们可把主要精力放在描述算法的逻辑上。
  3. 有数据说明机制,包括简单的(如标量和数组)与复杂的(如链表和层次结构)的数据结构。
  4. 有子程序定义与调用机制,用以表达各种方式的接口说明。

例:在数据A(1)~A(10)中求最大数和次大数,请用N—S流程图描述程序的算法。

在这里插入图片描述### 例:在数据A(1)~A(10)中求最大数和次大数,请用PAD图描述程序的算法。
在这里插入图片描述

例:在数据A(1)~A(10)中求最大数和次大数,请用PDL语言描算法。

  GET(a[1],a[2],...a[10]) 
  max=a[1];
  max2=a[2];
  FOR i=2 TO 10
     IF a[i]>max
        max2=max;
       max=a[i];
     ELSE 
       IF a[i]>max2
          max2=a[i];
       ENDIF
     ENDIF
  ENDFOR

设计规约与设计评审

• 软件设计阶段的主要输出是设计规约。为了确保文档的质量,还必须对设计文档进行评审。

设计规约

在这里插入图片描述
在这里插入图片描述

设计评审

• 软件设计的最终目标是要取得最佳方案
• “最佳”是指在所有候选方案中,就节省开发费用,降低资源消耗,缩短开发时间的条件,选择能够赢得较高的生产率、较高的可靠性和可维护性的方案
• 评审分正式评审和非正式评审两种
• 正式评审除软件开发人员外,还邀请用户代表和领域专家参加,通常采用答辩形式
• 非正式评审多少有些同行切磋的性质,不拘泥于时间和形式

设计评审的内容

1.可追溯性:即分析该软件的系统结构、子系统结构,确认该软件设计是否覆盖了所有已确定的软件需求,软件每一成分是否可追溯到某一项需求。
2.接口:即分析软件各部分之间的联系,确认该软件的内部接口与外部接口是否已经明确定义。部件是否满足高内聚和低耦合的要求。部件作用范围是否在其控制范围之内。
3.风险:即确认该软件设计在现有技术条件下和预算范围内是否能按时实现。
4.实用性:即确认该软件设计对于需求的解决方案是否实用。
5.技术清晰度:即确认该软件设计是否以一种易于翻译成代码的形式表达。
6.可维护性:从软件维护的角度出发,确认该软件设计是否考虑了方便未来的维护。
7.质量:即确认该软件设计是否表现出良好的质量特征。
8.各种选择方案:看是否考虑过其它方案,比较各种选择方案的标准是什么。
9.限制:评估对该软件的限制是否现实,是否与需求一致。
10.其它具体问题:对于文档、可测试性、设计过程等等进行评估。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值