系统设计
- 软件设计简介
- 概要设计
- 详细设计
- 软件设计的过程
- 面向对象设计的准则
- 模块构件设计
- 软件设计的基本原理和相关概念
- 模块化
- 通过模块化降低开发复杂度
- 最适当的模块数目
- 模块化的优点
- 抽象
- 封装和信息隐蔽
- 模块独立
- 耦合性(Coupling)
- 软件设计的原则之一:弱耦合
- 耦合的七个等级
- 模块化的原则
- 内聚性(Cohesion)
- 软件设计的原则之二:强内聚
- 内聚的七个等级
- 模块化的原则
- 应用场景
- 软件重用
- 软件成分的重用级别
- 10种典型的可重用软件成分
- 数据模型设计
- 数据持久化
- 数据库设计的步骤
- 数据字典
- 网上报名系统的数据建模——领域类图
系统分析与设计
1️⃣对网上报名系统进行需求建模后,进入到系统分析和概要设计阶段。
2️⃣在该阶段中,将在需求模型的基础上,对系统进行
静态建模以及
动态建模,最后构建出网上报名系统的软件架构。
3️⃣这主要体现在
对系统中对象抽象成类,进而对
类间的相互关系进行建模,而
系统内部行为建模则是由交互图进行描述。
软件设计简介
①软件设计采用自顶向下、逐次功能展开的设计方法,先完成总体设计,再完成各有机组成部分的设计。
②现在的软件设计分为:
1)数据/类设计:将分析-类模型变换成类的实现和软件实现所需要的数据结构。
2)软件体系结构设计:定义了软件的主要结构元素以及相互之间的关系。
3)接口设计:描述了软件内部、软件和协作系统之间以及软件同人之间如何通信。
4)部件级设计:将软件体系结构的结构性元素变换为对软件部件的过程性描述。
概要设计
①概要设计(总体设计):包括系统的总体设计文档、各模块的概要设计文档。在需求规格说明书的基础上描述系统的架构、功能模块的划分、模块接口的定义、用户界面设计、数据库设计等。
②在此阶段,应编写严谨的数据字典,合并功能重复的模块,或进一步分解出可复用的模块(最大限度的提取可以复用的模块),建立合理的结构体系,节省后续环节的工作量。
③尽管概要设计不涉及系统内部的实现细节,但它产生的实施方案与策略将会影响最终软件实现的成功与否,并影响今后软件系统维护的难易程度。
详细设计
①详细设计(具体设计):根据概要设计进行的模块划分,实现各模块的算法设计,实现用户界面设计,表单,需要的数据,数据结构设计的细化等。
②设计者的工作对象是一个模块,根据概要设计赋予的局部任务和对外接口,设计并表达模块的算法、流程、状态转换等内容。理想的详细设计完成后,应该让新手可以轻松的完成代码。
③详细设计文档中最重要的部分是模块的流程图、状态图、局部变量及相应的文字说明等。
④如果发现有结构调整(如分解出子模块)的必要,必须返回到概要设计阶段,将调整反映到概要设计文档中。
软件设计的过程
面向对象设计的准则
优秀设计就是使得系统在其整个生命周期中的总开销最小的设计, 其主要特点就是容易维护。
模块构件设计
①模块设计就是把软件按照一定的原则分解为模块层次,赋予每个模块一定的任务,并确定模块间的调用关系和接口。
②一个构件就是程序的一个功能要素,也称为模块。包括:程序的处理逻辑、需要的内部数据、保证构件被调用和实现数据传递的接口。
③模块分解的原则:
最大限度的提取可以重用的模块,建立合理的结构体系。
软件设计的基本原理和相关概念
模块化:软件系统越来越复杂,需要将其划分为若干部分分而治之。
抽象:为了降低问题的复杂度,以得到问题领域中较为简单的概念。
封装和信息隐蔽:为了避免某个模块的行为干扰同一系统中的其他模块,把必要的信息隐藏起来。
模块独立:每个模块只完成特定的单一功能,不同模块之间的联系尽可能少,尽可能减少公共变量和数据结构,有助于系统维护及软件的复用。
模块化
①模块是相对独立的程序体,是数据说明、可执行语句等程序对象(如类、过程、函数、子程序、宏等)的集合 。
②面向对象软件开发模式,很自然地支持模块的设计原理:对象就是模块。
③模块化就是把程序划分成若干个模块,每个模块完成一个子功能,把这些模块集中起来组成一个整体,可以完成指定的功能,满足问题的要求。
④模块之间既相互独立,又相互关联。
通过模块化降低开发复杂度
C(x):问题x的复杂性
E(x):解决问题x所需工作量
对于两个问题p1 和p2:
- 如果C(p1)>C(p2) 那么 E(p1)>E(p2)
问题越复杂解决问题所需要的花费更多 - C(p1+p2)>C(p1)+C(p2)因此E(p1+p2)>E(p1)+E(p2)
将复杂问题分解成可以多个子问题分别解决会更加容易(模块化思想的依据)
最适当的模块数目
如果我们无限制地划分软件,开发它所需的工作量会变得小到可以忽略?
结论:NO
模块数量增加时,只是使各个子模块的工作量之和有所减小 。
然而开发工作量还有很大一部分来自于模块间的接口和集成。
除了技术上的接口和集成,还包括人与人之间的沟通。
集成和沟通的开销到了一定程度就会成为开发工作量的主要部分。
模块化的优点
①可以使软件结构清晰,不仅容易设计也容易阅读和理解。
②可以使软件容易测试和调试,因而有助于提高软件的可靠性。
③能够提高软件的可修改性。
④有助于软件开发工程的组织管理。
抽象
①抽象就是抽出事物的本质特性而暂时不考虑它们的细节。
②抽象的过程是从特殊到一般的过程,上层概念是下层概念的抽象,下层概念是上层概念的精化和细化。
③软件开发过程的每一步都是对较高一级抽象的解作一次具体化的描述。
④面向对象方法支持过程和数据抽象。类是一种抽象数据类型。使用者无须知道类中数据元素的具体表示方法,就可以通过接口使用类中定义的数据。
⑤概要设计中的功能模块就是一个抽象化的功能黑盒子。
封装和信息隐蔽
每个模块都尽量对其他模块隐藏自己的内部实现细节。
~模块内部的数据和过程不允许其它不需要这些信息的模块使用。
~定义和实施对模块的过程细节和局部数据结构的存取限制。
~对象的封装性实现支持了信息隐藏。
~典型的信息隐藏:面向对象的访问控制符。
信息隐藏是实现抽象/模块化机制的基本支撑。
要求:应将单元接口设计得尽可能简单,并将单元对于环境的假设和要求降至最低。
1.测试期间和软件维护期间需要修改软件,使用信息隐蔽原理作为模块化系统设计的标准就会带来极大好处。
2.因为绝大多数数据和过程对于软件的其他部分而言是隐蔽的(也就是“看”不见的),在修改期间由于疏忽而引入的错误就很少可能传播到软件的其他部分。
模块独立
①模块独立的概念是模块化、抽象、封装和信息隐蔽概念的直接结果。
②为什么模块的独立性很重要呢?
1)有效的模块化(即具有独立的模块)的软件比较容易开发出来。独立的模块比较容易测试和维护。
③模块的独立程度可以由两个定性标准度量,这两个标准分别称为耦合和内聚。
1)高内聚:内部结构紧密。
2)低耦合:模块间关联和依赖程度尽可能小,与其他模块的接口简单。
耦合性(Coupling)
①耦合性是对一个软件结构中不同模块之间互连程度的度量。
②模块间耦合的强弱取决于接口的复杂性,即与信息传递的方式、接口参数的个数、接口参数的数据类型相关。不同模块之间相互依赖的越紧密则耦合度越高。
③耦合度影响系统的可理解性、可测试性、可靠性和可维护性。
软件设计的原则之一:弱耦合
为了提高模块的独立性,应该尽量降低模块之间的耦合度。
可行的举措有:
①两个对象应该通过类的接口实现耦合,而不应该依赖于类的具体实现细节(例如友元)。
②采用简单的数据传递方式,减少消息中包含的参数个数,降低参数的复杂程度(尽量使用基本类型作为接口的参数类型), 减少消息数。
为获得紧密的继承耦合,派生类应该是它的基类的一种具体化, 尽量多继承并使用其属性和服务,从而更紧密地耦合到其基类。
耦合的七个等级
1)非直接耦合
①如果两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的,这就是非直接耦合。
②这种耦合的模块独立性最强。
2)数据耦合
①如果一个模块访问另一个模块时,彼此之间是通过数据参数(不是控制参数、公共数据结构或外部变量)来交换输入、输出信息的,则称这种耦合为数据耦合。
②按数据耦合开发的程序界面简单、安全可靠。
③数据耦合是松散的耦合,模块之间的独立性比较强。在软件程序结构中至少必须有这类耦合。
3)标记耦合
①如果一组模块通过参数表传递记录信息,就是标记耦合。
②事实上,这组模块共享了这个记录,它是某一数据结构的子结构,而不是简单变量。这要求这些模块都必须清楚该记录的结构,并按结构要求对此记录进行操作。
③如果采取“信息隐蔽”的方法,把在数据结构上的操作全部集中在一个模块中,就可以消除这种耦合。
4)控制耦合
①如果一个模块通过传送开关、标志、名字等控制信息,明显地控制选择另一模块的功能,就是控制耦合。
②这种耦合的实质是在单一接口上选择多功能模块中的某项功能。
③对所控制模块的任何修改,都会影响控制模块。另外,控制耦合也意味着控制模块必须知道所控制模块内部的一些逻辑关系,这些都会降低模块的独立性。
①控制耦合属于中等程度的耦合,较之数据耦合,模块间的联系更为紧密。控制耦合不是一种必须存在的耦合。
②可以按如下的步骤排除控制耦合:
1.找出模块调用时所用的一个或多个控制变量。
2.在被调模块中,根据控制变量找出所有的流程。
3.将每一个流程分解为一个独立的模块。
4.将原被调模块中的流程选择部分移到上层模块,变为调用判断。
通过以上的变换,可以将控制耦合变为数据耦合。
5)外部耦合
①一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
②外部耦合引起的问题类似于公共耦合,区别在于在外部耦合中不存在依赖于一个数据结构内部各项的物理安排。
6)公共耦合
①若一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。
②公共的数据环境可以是全局数据结构、共享的通信区、内存的公共覆盖区、外存上的文件、物理设备等。
③若两个模块共享的数据很多时,可以使用公共耦合。
7)内容耦合
①若一个模块直接访问另一个模块的内部代码或数据,即出现了内容耦合。这是耦合程度最高的一种形式。
②如果出现以下情形,两个模块之间就发生了内容耦合:
1.一个模块访问另一个模块的内部数据。
2.一个模块不通过正常入口转到另一个模块的内部。
3.两个模块有一部分代码重叠(只可能出现在汇编程序中)。
4.一个模块有多个入口(这意味着一个模块有几种功能)。
模块化的原则
在模块划分时,应尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,完全不用内容耦合。
模块化设计的最终目标,是希望建立模块间耦合尽可能松散的系统。
在这样一个系统中,我们设计、编码、测试和维护其中任何一个模块,就不需要对系统中其他模块有很多的了解。
此外,由于模块间联系简单,发生在某一处的错误传播到整个系统的可能性很小。
内聚性(Cohesion)
①内聚:一个模块内各个元素(语句或语句段)彼此结合的紧密程度。
②模块内的高内聚往往意味着模块间的松耦合。模块内聚度越高,独立性越强,系统越容易理解和维护。
③理想内聚的模块是,只使用局部变量,完成一个功能。
④内聚和耦合都是模块化设计的有力工具,但是实践表明内聚更重要,应该把更多注意力集中到提高模块的内聚程度上。
软件设计的原则之二:强内聚
①内聚是对模块内部各个元素彼此结合的紧密程度,应该通过定义使每个模块都具有明确的功能,以提高模块内聚程度。
②在面向对象设计中存在下述3种内聚:
服务内聚:一个服务应该完成一个且仅完成一个功能。
类内聚:设计类的原则是,一个类应该只有一个用途,它的属性和服务应该是高内聚的。类的属性和服务应该全都是完成该类对象的任务所必需的。如果某个类有多个用途,通常应该把它分解成多个专用的类。
一般-特殊(继承)内聚:设计出的一般-特殊结构,应该符合多数人的概念,更准确地说,这种结构应该是对相应的领域知识的正确抽取。
紧密的继承耦合与高度的一般-特殊内聚是一致的。
内聚的七个等级
1)巧合内聚
①当模块内各部分之间没有联系,或者即使有联系,这种联系也很松散,则称这种模块为巧合内聚模块,又称为偶然内聚模块。
②这种模块的缺点:
1.首先是不易修改、测试和维护。
2.其次是这种模块的内容不易理解,很难描述它所完成的功能,增加了程序的模糊性。
③它是内聚程度最低的模块,在空间允许的情况下,不应使用这种内聚。
2)逻辑内聚
①这种模块把几种相关的功能组合在一起,每次调用时,由传送给模块的判定参数来确定该模块应执行哪一种功能。这种模块是单入口多功能模块。
②类似的有错误处理模块。它接收出错信号,对不同类型的错误打印出不同的出错信息。
③逻辑内聚模块比巧合内聚模块的内聚程度要高 。
④逻辑内聚的缺点:
1)它所执行的不是一种功能,而是执行若干功能中的一种,因此它不易修改。
2)另外,当调用时需要进行控制参数的传递,这就增加了模块间的耦合程度。
3)而将未用的部分也调入内存,这就降低了系统的效率。
3)时间内聚
①时间内聚又称为经典内聚。
②这种模块大多为多功能模块,但模块的各个功能的执行与时间有关,通常要求所有功能必须在同一时间段内执行。
③例如初始化模块和终止模块。初始化模块要为所有变量赋初值,对所有介质上的文件置初态,初始化寄存器和栈等,因此要求在程序开始执行的最初一段时间内,模块中所有功能全部执行一遍。
④也属于低内聚度的类型。
4)过程内聚
①如果一个模块内的处理是相关的,而且必须以特定次序执行,则称这个模块为过程内聚模块。
②使用流程图做为工具设计程序的时候,常常通过流程图来确定模块划分。把流程图中的某一部分划出组成模块,就得到过程内聚模块。
③例如,我们把流程图中的循环部分、判定部分、计算部分分成三个模块,这三个模块都是过程内聚模块。
(5)通信内聚
①如果一个模块内各功能部分都使用了相同的输入数据,或产生了相同的输出数据,则称之为通信内聚模块。
②通信内聚和过程内聚都属于中内聚度模块。
(6)信息内聚
这种模块完成多个功能,各个功能都在同一数据结构上操作,每一项功能有一个唯一的入口点。
7) 顺序内聚
①如果一个模块内的处理元素和同一个功能密切相关,而且这些处理必须顺序执行,通常一个处理元素的输出数据作为下一个处理元素的输入数据。这种内聚称为顺序内聚。
②属于高内聚度模块。
(8)功能内聚
一个模块中各个部分都是完成某一具体功能(单一功能)必不可少的组成部分,或者说该模块中所有部分都是为了完成一项具体功能而协同工作,紧密联系,不可分割的。则称该模块为功能内聚模块。
①功能内聚是内聚度最高的类型。
②功能内聚模块的优点是它们容易修改和维护,因为它们的功能是明确的,模块间的耦合是简单的。
模块化的原则
在模块设计时,应力争做到高内聚,并能够辨别出低内聚的模块,加以修改使之提高内聚度,降低耦合度。
①设计功能独立单一的模块。
②控制使用全局数据。
③模块间尽量传递数据型信息。
应用场景
函数
高内聚:尽可能类的每个成员方法只完成一件事(最大限度的聚合)。
低耦合:减少类内部,一个成员方法调用另一个成员方法。
类
高内聚低耦合:减少类内部,对其他类的调用。
功能块
高内聚低耦合:减少模块之间的交互复杂度(接口数量,参数数据)。
软件重用
重用也叫再用或复用,是指同一事物不作修改或稍加改动就多次重复使用。
重用有两方面的含义:
一是尽量使用已有的类;
二是在设计新类的协议时考虑将来的可重用性。
软件重用可分为3个层次:
①知识重用(例如,软件工程知识的重用)。
②方法和标准的重用(例如,面向对象方法或国家制定的软件开发规范的重用)。
③软件成分的重用。
软件成分的重用级别
软件成分重用的3个级别:
(1)几种形式的代码重用
源代码剪贴:几乎无法跟踪原始代码块的修改
源代码包含#include :重新编译都用最新源代码
继承:可扩充或修改库中的类而不影响原有的代码
(2) 设计结果重用
重用某个软件系统的设计模型。
(3) 分析结果重用
重用分析模型, 例如,把一个应用系统移植到完全不同的软硬件平台上。
10种典型的可重用软件成分
(1) 项目计划:软件质量保证计划。
(2) 成本估计:不同项目中类似功能的成本估算。
(3) 体系结构:事务类处理体系结构。
(4) 需求模型/规格说明:对象模型,数据流图。
(5) 设计:体系结构、数据、接口和过程设计。
(6) 源代码:兼容的程序构件。
(7) 用户文档和技术文档:部分重用。
(8) 用户界面:GUI 可占应用程序的60%代码量。
(9) 数据: 记录结构,文件和完整的数据库。
(10)测试用例:与重用设计或代码相关的用例。
数据模型设计
在设计阶段要对存储的数据及其结构进行设计。
首先在高层(用户的角度)建立数据模型,然后逐步将这个数据模型变为将来进行编码的模型。
数据模型是系统内部的静态数据结构,包括:数据对象、数据属性和关系。(与领域类图对应)
数据模型可分为:
概念数据模型:以问题域的语言解释数据模型,描述概念。
逻辑数据模型:使用中立语言进行描述,缓解二者差异。
物理数据模型:以解系统的语言解释数据模型,描述实现。
数据持久化
1️⃣数据的持久化是指系统中要使用到的永久性数据或是系统产生的数据处理结果,将以什么样的形式进行保存。
2️⃣目前的较为常见的主要有两种:
①数据库管理系统(DBMS):以数据库形式存储。可以实现数据的共享和安全存取。
②文件存储模式:以文件形式存储。使用方便,例如系统的配置信息常以配置文件的形式存在,XML文件。但是面对大量数据的存取,文件在数据共享、存取速度、安全性等方面有所欠缺。
数据库设计的步骤
1.需求阶段的数据收集,构建数据字典,明确哪些数据需要存储,要完成什么样的数据处理功能。
2.概念结构设计,用E-R图描述现实世界的概念模型。
3.逻辑结构设计,将概念模型转换为能够被DBMS支持的数据模型。
4.物理结构设计,明确选取合适的DBMS,搭建应用环境,配置数据库服务器,设计数据的存储结构和存取方法,如索引、视图、存储过程、触发器等。
5.系统实施,建立数据库,组织数据入库,编写和调试程序,运行测试。
6.运行维护,维护数据库安全性与完整性,根据需求改正和改进数据库的功能。
数据字典
①描述数据库中的数据元素、组成结构体的复杂数据元素、重复的数据项、一个数据项的枚举值以及可选的数据项等。
②在面向对象的分析方法中,需求阶段用领域类图来代替数据字典。但是在数据建模阶段,通过对数据的语义唯一性定义等方面,还是能够指导整个项目的开发过程。
③编写方法:解读业务分析报告,根据用例进行数据的归类,形成不同的数据集,定义元素的唯一性说明。
④常见格式如下: 数据集名称
网上报名系统的数据建模——领域类图
根据用户访谈得知,更新需求。
1.用户需添加“邮箱” 、“身份证号”。
2.单位需增加“负责人”。
3.参赛单位信息后台不做管理,参赛运动员报名中增加“领队”、“医生”、“工作人员”。
4.赛事需加入赛事状态一项,用于运动员报名操作。修改后的领域类图
领域类图描述的是系统中的数据对象,又称为 Object Model,属于概念级别的模型,需要映射为表(Data Model)才能被计算机存储。
根据领域类图,可以进行数据库设计
编写表结构说明
1、用户表(t_user)
2、单位表(t_dept)
3、竞赛项目表(t_item)
4、运动员表(t_athlete)
5、赛事表(t_game)
6、赛事项目表(t_gameitem)
7、运动员报名信息表(t_signup)