一、概述
软件设计阶段用比较抽象概括的方式确定目标系统如何完成预定的任务,即确定系统的物理模型。
回答系统 “做什么”。
软件设计是将需求转化为最终产品的唯一途径,是后续开发和维护工作的基础。
1、软件设计过程
从工程管理角度,软件设计分两个阶段:
第一阶段,总体设计/概要设计。
站在全局高度,从较抽象的层次上寻找目标系统的各种可能的实现方案,从若干合理方案中推荐一个最佳实现方案,为其设计合理的软件结构,用较低成本开发出较高质量的软件系统。
第二阶段,详细设计/过程设计。表示每个模块的算法和局部数据结构。
2、软件设计的原理
五个基本原理:模块化 、抽象 、逐步求精 、信息隐蔽 、模块独立
(1)模块化
模块是由边界元素限定的相邻程序元素的序列,是构成程序的基本构件。
模块化就是把程序划分成独立命名且独立访问的模块,每个模块完成一个子功能,这些模块集成起来构成一个整体,完成指定功能满足用户需求。
模块化使软件结构清晰、易于设计、理解、测试和调试,有助于提高软件的可靠性,也有助于软件开发工程的组织管理。
(模块的划分)
(2)抽象
抽象就是抽出事物的本质特性而暂时不考虑它们的细节,是人类认识复杂现象过程中使用的最强有力的思维工具。
在高抽象层次上,概括描述问题的解法; 在低抽象层次上,采用过程化的方法。
抽象分为:数据抽象和过程抽象。
(3)逐步求精
为了能集中精力解决主要问题而尽量推迟对问题细节的考虑。
是一项把一个时期内必须解决的种种问题按优先级排序的技术,确保每个问题都在适当的时候被解决。
软件体系结构自顶向下,对过程细节和数据细节逐层细化,直至用编程语言实现。
(4)信息隐蔽
每个模块的细节对其它模块隐蔽,模块中包含的信息不允许其他不需要这些信息的模块使用。
“隐藏”定义并施加了对模块内部过程细节和局部数据结构的访问限制。
修改时偶然引入错误所造成的影响可局限在模块内,不致波及到软件的其它部分。
(5)模块独立
“模块独立”是模块化、抽象、逐步求精和信息隐蔽的直接结果,也是完成有效模块设计的基本标准。
模块独立性:软件系统中每个模块只涉及软件要求的具体子功能,和其它模块的接口是简单的。要求完成独立的功能、符合信息隐蔽和局部化原理、模块间关联和依赖尽量小。
(6)模块独立性的度量
结构化分析方法用两个准则度量模块独立性,即模块的内聚和模块间的耦合。
耦合性:模块间互相连接的紧密程度的度量,取决于模块之间接口的复杂度、调用方式以及哪些信息通过接口。
非直接耦合:两个模块之间没有直接关系,它们之间的联系完全通过主模块的控制和调用实现。
数据耦合:一个模块访问另一个模块时,彼此间通过简单数据参数(不是控制参数、公共数据结构或外部变量)来交换输入、输出信息。
标记耦合:又称特征耦合,一组模块通过参数表传递记录信息,该记录是某一数据结构的子结构,不是简单变量。
控制耦合:一个模块通过传送开关、标志、名字等控制参数,明显地控制选择另一模块的功能。增加了理解和编程的复杂性,调用模块必须知道被调模块的内部逻辑,增加了相互依赖。
外部耦合:一组模块都访问同一全局简单变量,而不是通过参数表来传递信息,称为外部耦合。 外部耦合中不存在依赖于一个数据结构内部各项的物理安排。 外部耦合必不可少,但这种模块的数量应尽量减少。
公共耦合:一组模块都访问同一个公共数据环境,它们之间存在着错综复杂的联系。公共的数据环境可以是: 全局数据结构 共享的通信区 内存的公共覆盖区。
内容耦合:一个模块直接访问另一模块的内部数据; 一个模块通过非正常入口转到另一模块内部; 两个模块有一部分程序代码重迭; 一个模块有多个入口。
内聚性:内聚是一个模块内部各元素彼此结合的紧密程度的度量;
功能内聚:一个模块中各个部分都是完成某一具体功能必不可少的组成部分。 模块中所有部分为了完成一项具体功能而协同工作,紧密联系、不可分割,则称功能内聚模块。
信息内聚:信息内聚模块完成多个功能,各个功能都在同一数据结构上操作,每一项功能有一个唯一的入口点。
通信内聚:如果一个模块内各功能部分都使用了相同的输入数据,或产生相同的输出数据,则称为通信内聚模块。
过程内聚:模块内各处理成分相关,且必须以特定的次序执行,称为过程内聚。 使用程序流程图作工具设计程序时,把流程图中某一部分划出组成模块,得到过程内聚模块。
时间内聚:又称“经典内聚”,模块内各功能的执行与时间有关,要求所有功能必须在同一时间段内执行。 例如,初始化模块和终止模块就是时间内聚模块。
逻辑内聚:把几种相关的功能组合在一起,每次被调用时,由传送给模块的判定参数确定该模块应执行哪一种功能。
巧合内聚:当几个模块恰好有一段相同的代码,将它们抽取出来形成单独的模块,即为巧合内聚模块。 这种模块没有独立功能,各部分之间没有联系或联系很松散。
独立性度量:高内聚模块意味着与其它模块间松散耦合、与其它模块高耦合的模块意味着弱内聚。
实践表明内聚更重要,应该把更多注意力集中到提高模块的内聚程度上。
设计目标:高内聚、弱耦合
(7)软件设计的启发式规则
①改进软件结构提高模块独立性 ②模块规模应该适中 ③力争降低接口的复杂程度 ④设计单入口单出口的模块(避免内容耦合) ⑤模块功能可预测 ⑥深度、宽度、扇出和扇入适当 ⑦模块的作用范围应在控制范围之内
二、总体设计
站在全局高度,从较抽象的层次上寻找目标系统的各种可能的实现方案,从若干合理方案中推荐一个最佳实现方案,为其设计合理的软件结构,用较低成本开发出较高质量的软件系统。
1、总体设计的过程
设想供选择的方案
选取合理的方案 推荐最佳方案
制定详细的实现计划
功能分解(精化DFD)
设计软件结构(层次、模块、接口)
设计数据库
制定测试计划
编写文档
审查和复审
2、描绘软件结构的工具
总体设计确定软件系统的结构和各模块功能及模块间联系,自顶向下、逐步求精,把一个复杂问题分解和细化成一个由许多模块组成的具有层次结构的软件系统。
表示软件结构的图形工具 ①层次图②HIPO图 ③结构图
层次图:矩形框代表模块,框间连线表示调用关系
HIPO图:HIPO图采用功能框图和PDL来描述程序逻辑,由两部分组成:可视目录表(H图)和IPO图。H图给出程序的层次关系;IPO图为程序各部分提供工作细节,为层次图的每一功能框详细地指明输入(I)、处理(P)及输出(O)。
结构图(Structure Chart):概要设计中描绘软件结构的图形工具
根据系统结构特征分为两种典型形式:
变换型结构图:针对数据处理问题取得数据、变换数据和给出数据的三步过程,将结构图分为输入、中心变换和输出三部分。
事务型结构图:根据事务处理的特点和性质,由“事务中心模块”按所接受事务的类型,选择调度某一个事务处理模块执行,然后给出结果。
3、面向数据流的设计方法
又称“结构化设计方法(SD)”,以数据流图为基础,定义了把DFD变换成软件结构的不同映射方法。
4、软件设计的优化
设计人员应致力于开发能够满足所有功能和性能要求,而且按照设计原理和启发式规则衡量是值得接受的软件。
对初始SC的模块进行调整、修改,得到易于实现、测试和维护的软件结构,产生设计文档的最终SC。
三、人机交互界面设计
人机界面HCI(Human Computer Interface)也称用户界面,是界面设计的一个部分。
对于交互式系统来说,人机界面设计和数据设计、体系结构设计、过程设计一样重要。
界面设计的质量要求:
可用性:使用简单,有帮助功能,响应快,有容错能力
灵活性:用户可定制和修改界面,按需要提供响应信息
可靠性:保证可靠地使用系统,保证程序和数据安全
1、设计问题
系统响应时间
用户帮助设施:集成的帮助设施、附加的帮助设施
出错信息处理:出现问题时给出的“坏消息”,提示或警告
命令交互
2、设计规则
(1)数据输入界面
数据输入界面是系统的一个重要组成部分,占用户的大部分使用时间。
目标:尽量简化用户的工作、减少输入的出错率。
数据内容应根据其使用频率、重要性、输入次序进行组织。
设计时要尽可能减少用户的记忆负担,防止用户输入出错,尽可能增加数据自动输入。
对话规则:
明确的输入:只有当用户按下输入的确认键时,才确认输入。
明确的动作:在表格项间自动地跳跃/转换并不总是可取的,使用TAB键或回车键控制在表格项间的移动。
明确的取消:如果用户中断了一个输入序列,已输入的数据不要马上丢弃。
确认删除:为避免错误的删除可能造成的损失,在键入删除命令后,必须进行确认再执行删除操作。
提供反馈:若一个屏幕上可容纳若干输入内容,可将用户先前输入的内容仍保留在屏幕上,以便随时察看。
提供复原 (Undo):应允许用户恢复输入以前的状态,这在编辑和修改错误的操作经常用到。
允许编辑:在一个文件输入过程中或输入完成后,允许用户对其编辑。
自动格式化:用户可以采用自由格式输入,对空格不敏感。
提示输入的范围:显示有效的集合及其范围。
(2)数据显示界面设计
数据显示界面包括图形显示、报告、屏幕查询和文件浏览等。
进行数据输出显示设计,应了解数据显示的要求,解决应显示哪些数据、一次显示多少信息的问题。
显示信息应适当,不要过于拥挤。
可以根据屏幕的大小,划分若干区域,每个区域显示不同信息。
显示内容的准则:
显示的数据应与用户执行的任务有关,只显示必需的数据,无直接关系的省略。
在一起使用的数据应显示在一起。
每一屏的数据量,包括标题、栏题等,不应超过整个屏幕面积的30%。
屏幕布局规则:
提供明了的标题、标栏及其它提示信息,多个显示界面应建立统一格式
尽量少用代码和缩写,遵循用户习惯
采用颜色、字体、字号、下划线等方式强化重要数据
(3)控制界面的设计
目的:让用户主动地控制计算机上软件系统的工作,能够很容易地访问计算机的各种设备。
主要方式:控制对话、菜单、功能键、图标、窗口、命令语言等。
用控制对话选择操作命令
控制对话可以是简单问答形式,系统提出是否需要某个操作,用户以Y/N的方式回答。
复杂的对话形式是基于菜单的系统,通常用户在菜单下做出应答有两种方式:
①使用应答码对屏幕显示的菜单做出选择,应答码可以是数字或字符。
②使用鼠标器按钮或光标移动键对高亮度菜单选择条逐行选择,按回车键确定当前选定的菜单选择条。
用功能键定义操作命令
功能键是与菜单等效的硬件,通过定义和使用键盘上特定的键来选择,节省屏幕空间。
功能键可以用硬编码,也可以用软编码。
①硬编码:将功能键的操作固定到某个特殊键,该键以用户能看懂的操作进行标记。
②软编码:命令调用通过应用程序分配到各个功能键上,多数系统功能键都是软编码的。
用图标表示对象或命令
为了使得用户能够识别一个图符所表示的物体或命令,图标应当是逼真的。
有时图标可能会有多义性,对于同一个图标,不同的人有不同的解释。为了防止多义性,在图标下加文字解释。
用窗口划分屏幕
若要求同时具有许多不同的界面,或同一对象有多个视图,这就需要窗口的支持。
窗口把物理屏幕划分成几部分,在屏幕上可以同时进行不同的操作。
用户可在不同的窗口中运行多个进程,窗口以这种方式允许多任务处理进入“挂起/继续”状态。
在办公室的环境中,需要并行地处理多个任务,窗口就很适合于这种工作。
命令语言
命令语言是潜在的、最强有力的控制界面,通过名字直接使用其功能,命令组合使系统功能更加灵活。
所有的命令语言都有一个词典和一个语法:词典给定单词的集合;语法说明单词组合方式的规则。
优点:易于自动化,节省屏幕空间、启动快速、高效、对系统要求低、易于远程调用、对键盘友好。
四、过程设计
即详细设计、模块设计,是编码的先导
主要任务:
表达算法的过程,写出模块的详细过程性描述;
确定每一模块的数据结构(视图);
确定模块接口细节;
编写详细设计说明书;
编写测试计划,设计模块测试用例。
1、结构程序设计
过程设计不仅要正确地描述每个模块的具体实现,更重要的是设计出的处理过程应尽可能简明易懂。
结构程序设计采用自顶向下、逐步求精的设计方法和单入口、单出口的控制结构。
2、过程设计的描述工具
详细设计阶段,要决定各个模块的实现算法,并精确地表达这些算法。
图形工具:程序流程图、 N-S盒图、 PAD问题分析图
表格工具:判定表
语言工具:过程设计语言PDL
(1)程序流程图
程序流程图又称为程序框图,历史最悠久,使用最广泛,也最混乱。
独立于程序设计语言,直观、易学,可以表示五种基本控制结构。
用箭头代表程序的控制流,程序员可以不受任何约束,随意转移控制。
(2)N-S盒图
用方框图代替传统程序流程图,规定图形构件:
(3)PAD问题分析图
用二维树型结构表示程序的控制流
(4)判定表
用于表示程序的静态逻辑,能够清晰地表达复杂的条件组合与应做动作之间的关系。
(5)判定树
判定树是判定表的变种,形式简单,易于掌握和使用,但简洁性不如判定表。
数据元素的同一个值重复多遍,越接近树叶端重复次数越多。
(6)PDL过程设计语言
用于描述功能模块的算法设计和加工细节,是一种伪码。
语法规则分为“外语法”——有严格的关键字,用于定义控制结构和数据结构,分割正文
和“内语法”——自然语言描述处理特性,灵活、主要精力放在描述算法上。
五、程序复杂度
度量详细设计后的模块质量时,软件设计的基本原理可作为定性度量的依据,定量度量方法仍处于研究阶段。
目前广泛使用的定量度量程序复杂度的方法:McCabe方法(环路度量法)和 Halstead方法
定量度量的价值:估算开发工作量和软件中故障的数量,比较不同算法的优劣,还可以作为模块规模的精确限度。
1、环路度量法
基于程序控制流的复杂性度量方法,又称“环路度量”,度量结果称为程序的环路复杂度。
McCabe方法认为程序的复杂性很大程度上取决于程序图的复杂性,它以图论为工具,先画出流图,然后用该图的环路数作为程序复杂性的度量值。
广泛应用于:程序设计和管理指南,网络复杂性的度量,测试的辅助工具等。
程序控制流图
符号○:流图的结点,表示一个或多个内部无分支的PDL语句或源程序语句; 箭头→:流图的边,表示控制流的方向。
环路复杂度V(G)=E-N+2,其中E是流图中边数,N是节点数;
环路复杂度V(G)=P+1,其中P是流图中判定节点的数目。
环路复杂度取决于程序结构的复杂度,是对测试难度的一种定量度量,环路复杂度高的程序往往最困难、最容易出问题。
大量实践研究表明,模块规模以V(G)≤10为宜,也就是说,V(G)=10 是模块规模的一个更科学更精确的上限。
2、Halstead方法
根据程序中运算符和操作数的总数来度量程序的复杂程度。
详细设计完成后,可以知道程序中使用的不同运算符个数n1,以及不同操作数个数n2,Halstead给出预测程序长度H的公式:
多次验证表明,预测的长度与实际长度非常接近。
3、面向数据结构的设计方法
程序加工的是数据,程序表述的算法在很大程度上依赖于作为基础的数据结构。
数据结构影响软件结构和过程,可以利用输入数据结构和输出数据结构来推导程序结构。
Jackson方法和Warnier方法是最著名的两个面向数据结构的设计方法。
JSP方法(Jackson Structured Programming)是一种面向数据结构、数据驱动的程序设计方法。按输入、输出和内部信息的数据结构进行设计,将数据结构的描述映射成程序结构。适用于详细设计阶段,设计每个模块的处理过程。
程序中实际使用的数据结构种类繁多,但它们的数据元素彼此间的逻辑关系却只有顺序、选择和重复三种,因此,逻辑数据结构也只有这三种。顺序结构、选择结构、循环结构。
4、JSP方法和SD方法的比较
SD方法:面向数据流的设计方法
JSP方法:面向数据结构的设计方法
共同点:都是数据信息驱动的,将数据表示转换成软件表示。
不同点:SD方法利用数据流图,生成软件结构的描述;
JSP方法根据数据结构,生成程序处理过程的描述。
JSP方法的优点:简单、适合于规模不大的系统,建立了问题的数据结构之后,可直接推导出相应的程序结构。
JSP方法是一种适用于小型系统的程序设计方法,在设计简单数据处理系统时非常方便,但设计复杂程序时,常常遇到输入数据可能有错、条件不能预先测试和数据结构冲突等问题。