#设计过程
#总体设计的两个阶段
- 系统设计阶段:确定系统的具体实现方案
- 结构设计阶段:确定软件结构
🔖系统设计关注:物理组成、成本、工期,这些都是方案的组成部分。
#典型的总体设计过程
- 设想供选择的方案
- 选取合理的方案
- 推荐最佳方案
- 功能分解
- 设计软件结构
- 设计数据库
- 制定测试计划
- 书写文档
- 审查与复审
🔖文档包括:系统说明、用户手册、测试计划、详细的实现计划和数据库的设计结果。
#设计原理
#模块化
模块化就是把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能,把这些模块集成起来构成一个整体,可以完成指定的功能满足用户的需求。
模块化的理论依据是 $E(P_1+P_2)>E(P_1)+E(P_2)$,$E(P)$ 代表解决 P 问题的成本,即把复杂的问题分解成许多容易解决的小问题,从而降低成本。但随着模块数的增多,接口成本会随之增加,所以应根据这两个因素,得到最适当的模块数。
#抽象
抽出事务的本质特性——事物、状态或过程之间总存在着某些相似的方面(共性)——而暂时不考虑它们的细节,它是人类认识复杂事物时最有力的思维工具。从抽象到具体分析和构造软件的层次结构,是进行软件设计的一种有效的方法。
复杂的动态系统:高级的抽象概念构造和理解 $\rightarrow$ 较低的层次 $\rightarrow$ ... $\rightarrow$ 最低层次、具体元素
#逐步求精
“为了能集中精力解决主要问题而尽量推迟对问题细节的考虑。”
帮助软件工程师把精力集中在与当前开发阶段最相关的方面;目前不需要考虑的细节留到以后考虑;把一个时期内必须解决的问题按照优先级排序;自顶向下的策略。
求精实际上是细化过程。抽象使得设计者能够说明过程和数据,同时却忽略低层细节。事实上,可以把抽象看作是一种通过忽略多余的细节同时强调有关的细节,而实现逐步求精的方法。求精帮助设计者在设计过程中揭示出低层细节。
#信息隐藏与局部化
局部化是指把一些关系密切的软件元素物理地放得彼此靠近。在模块中使用局部数据是局部化的一个例子。 信息隐藏指的是应该这样设计和确定模块,使得一个模块内包含的信息(过程和数据)对于不需要这些信息的模块来说,是不能访问的。
#模块独立
“模块独立”概念是模块化、抽象、逐步求精和信息隐藏等概念的直接结果,也是完成有效的模块设计的基本标准。
模块的独立程度可以由两个定性标准来度量,这两个标准分别称为耦合(Coupling)和内聚(Cohesion)。
- 耦合衡量不同模块彼此间互相依赖(连接)紧密程度
- 内聚衡量一个模块内部各个元素彼此结合的紧密程度
📌好的设计应力争:高内聚低耦合
#耦合
耦合的强弱取决于模块间接口的复杂程度,进入或访问一个模块的点,以及通过接口的数据。 在软件设计中应该追求尽可能松散耦合的系统。在这样的系统中可以研究、测试或维护任何一个模块,而不需要对系统的其他模块有很多了解。此外,由于模块间联系简单,发生在一处的错误传播到整个系统的可能性就很小。
因此,模块间的耦合程度的强弱将直接影响系统的可理解性、可测试性、可靠性和可维护性。
-
数据耦合
一个模块访问另一个模块时,彼此之间是通过简单数据参数 (不是控制参数、公共数据结构或外部变量) 来交换输入、输出信息。
-
控制耦合
传递的信息中有控制信息,尽管有时这种控制信息是数据的形式。控制耦合可以把模块适当分解后用数据耦合代替它。
-
特征耦合
把整个数据结构作为参数传递,而被调用的模块仅需使用其中一部分数据。
-
公共环境耦合
一组模块都访问同一个公共数据环境,公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区等。
-
内容耦合
最高程度的耦合。出现以下情况之一就是发生了内容耦合:
- 一个模块直接访问另一个模块的内部数据
- 一个模块不通过正常入口转到另一模块内部(goto 语句)
- 两个模块有一部分程序代码重迭(只可能出现在汇编语言中)
- 一个模块有多个入口(一个模块有几种功能)
🔖公共环境耦合的复杂程度随耦合模块的个数增加而显著增加。若只是两模块间有公共数据环境,则公共耦合有两种情况:松散公共环境耦合和紧密环境公共耦合。
- 松散公共环境耦合。一个模块往公共环境送数据,一个模块从中取数据,这是数据耦合的一种形式。
- 紧密环境公共耦合。两个模块都既往公共环境中送数据又从中取数据,介于数据耦合和控制耦合之间。
📌设计原则:尽量使用数据耦合,少用控制耦合和特征耦合,限制公共环境耦合的范围,完全避免内容耦合。
#内聚
内聚标志一个模块内各个元素彼此结合的紧密程度,理想内聚的模块只做一件事情。设计时应该力求做到高内聚,通常中等程度的内聚也是可以采用的,而且效果和高内聚相差不多。
内聚和耦合是密切相关的,模块内的高内聚往往意味着模块间的松耦合。实践表明内聚更重要,应该把更多注意力集中到提高模块的内聚程度上。
低内聚
-
偶然内聚
一个模块任务间关系松散或者没有关系。
-
逻辑内聚
模块完成的任务在逻辑上属于相同或者相似的一类(如都是输出)。
-
时间内聚
包含的任务必须在同一段时间内执行 (如初始化模块)。
中内聚
-
过程内聚
一个模块内的处理元素相关,并且以特定的次序执行。通过研究程序流程图划分的模块一般是过程内聚。
-
通信内聚
模块中所有元素都使用同一个输入数据和/或产生同一个输出数据。
高内聚
-
顺序内聚
一个模块内的处理元素和同一个功能密切相关,并且必须顺序执行(前一个处理的输出是后一个处理的输入)。
-
功能内聚
模块内所有处理元素属于一个整体,完成一个单一的功能。
🎈判断内聚方式的方法:模块是否只完成单一功能,是则为功能内聚,否则考虑模块内各组成部分的关系;如果是数据流的关系,那么考虑次序是否重要,是则为顺序内聚,否则为通信内聚;如果是控制流的关系,那么考虑次序是否重要,是则为过程内聚,否则为时间内聚;如果既不是数据流也不是控制流,那么考虑功能间逻辑是否类似,是则为逻辑内聚,否则为偶然内聚。
#表示软件结构的图形工具
#层次图(H 图)和 HIPO 图
在层次图中一个矩形框代表一个模块。框间的连线表示调用关系(位于上方的矩形框所代表的模块调用位于下方的矩形框所代表的模块)。
🔖H 图与需求分析时介绍的层次方框图看起来是一样的,但内容和含义完全不同。H 图方框间的连线表示调用关系,而不是组成关系。
HIPO 图:带编号的 H 图(最顶层的方框不加编号) + 带编号的 IPO 图。
#结构图
图中一个方框代表一个模块,框内注明模块的名字或主要功能;方框之间的箭头(或直线)表示模块的调用(call)关系。
在结构图中通常还用带注释的箭头表示模块调用过程中来回传递的信息,可以利用注释箭头尾部的形状来区分传递的信息是数据还是控制信息:尾部是空心圆表示传递的是数据;实心圆表示传递的是控制信息。