软件设计工程
一、软件设计简介
定义:为软件系统的架构,组件,接口和其它特性的定义过程及该过程的结果,解决“如何做”How的问题。
软件设计方法包括:
- 结构化设计SD
- 面向对象的设计OOD
软件设计包括以下活动:
- 软件架构设计(概要设计,顶层设计)
- 体系结构设计
- 数据设计
- 接口设计
- 软件详细设计(组件设计,过程设计)
- 不包括:创新设计
软件质量可以用质量属性来描述。FURPS质量属性:
- Functionality: 功能性
- Usability: 可用性
- Reliability: 可靠性
- Performance: 性能
- Serviceability: 可维护性
二、设计技术
抽象:
侧重于解决特定问题的细节,忽略不相关的底层细节。
设计开始时应提高软件的抽象层次,按抽象级别从高到低进行软件设计。
细化:
与抽象相对的概念,从软件定义到实现,每进展一步都可以看成是对软件设计方案的抽象化过程的一次细化。
自顶向下,逐步细化:
- 最高的抽象层次:用问题所处环境的语言描述
- 较低的抽象层次:用面向问题的术语,面向现实的术语描述
- 最低的抽象层次:用某种程序设计语言描述
设计模式:
- 创建型模式
- 结构型模式
- 行为型模式
模块化:
- 理论依据:分解问题后的复杂性/工作量的总和<原问题复杂性/工作量
- 模块分解并不是越小越好:随着模块数增加,单个模块的规模减小了,但是模块之间的关系复杂程度会增加,设计模块间接口的工作量也将增大。
如何衡量模块化设计水平?模块化设计标准:
- 模块化分解性:分解子问题的系统机制
- 模块化组合性:现有组件可以组装成系统
- 模块化可理解性:一个模块可以作为一个独立单元来使用
- 模块化连续性:系统需求的小变化只引起单个模块变化
- 模块化保护:模块内的异常情况只影响自身模块
信息隐藏:
模块内的信息不可以被不需要这些信息的其它模块访问。
功能独立:
- 只解决特定的子功能
- 接口得到简化
功能独立的两个定性衡量标准:
- 内聚性:模块的功能相对强度
- 耦合性:模块之间的相互依赖程度
独立性强的模块:高内聚,低耦合
耦合的7种类型:
- 非直接耦合:两个模块没有直接联系,完全是通过主模块的控制和调用实现的
- 数据耦合:仅通过模块参数交换信息,且交换的都是简单数据
- 标记耦合:通过参数表,传递一个数据结构的一部分
- 控制耦合:一个模块传递给另一个模块的参数中,包含了控制信息,用于控制接受模块的执行情况
- 外部耦合:模块通过除软件以外的环境(如I/O)连接
- 公共耦合:一组模块访问一个公共数据环境
- 内容耦合:一个模块对另一个模块的内容(数据,代码段)进行了直接引用或修改,两个模块共享一部分代码
内聚的7种类型:
- 巧合内聚:又称偶然内聚,语句段十分松散,无联系
- 逻辑内聚:把几种功能组合在一起,由传入模块的控制参数来决定执行哪一种功能
- 时间内聚:一个模块包括了需要在同一时间段执行的多个任务
- 过程内聚:一个模块内的各个部分按照特定的次序执行
- 通信内聚:一个模块中的各个部分使用同一个输入数据或产生同一个输出数据
- 顺序内聚:必须按照先后顺序执行,后一个部分与前一个部分密切相关
- 功能内聚:模块完成一个功能
重构:
不改变组件功能的条件下,简化组件设计。
三、设计模型
- 体系结构设计:强调系统的:可理解性,可维护性,可扩展性
- 模式
- 风格
- 框架(如MVC Struts)
- 数据设计
- 接口设计
- 组件设计
体系结构设计:
将模式(即,针对特定问题的解决方案)划分成三类:
- 体系结构模式:软件系统的基本结构组织形式或方案
- 设计模式(23种):构件相互通信的结构
- 惯用法:与编程语言相关的低级模式
架构风格分类:
- 数据中心架构:
- 数据流架构
- 调用和返回架构:
- 可分为主程序/子程序架构(所以程序组件都在同一台计算机上),远程过程调用架构(主程序或子程序的各组件分布在多台计算机上)两类
- 需要理解:深度,宽度,扇入,扇出:
- 面向对象架构:封装了数据和对数据的操作
- 层次架构:每一层为上一层提供服务,并作为下一层的客户。每一层最多只影响两层,只需提供接口,允许各层用不同方法实现。
另一种分类方法:
- 单主机结构
- 分布式结构
- 多处理器体系结构
- 客户机/服务器体系结构(B/S C/S架构)
- 分布式对象体系结构
- 代理
两层C/S架构:
- 瘦客户机模型:除数据表示以外的操作都在服务器执行。客户机只负责数据表示。
- 胖客户机模型:服务器只负责管理数据,客户机实现应用逻辑和与系统交互。
三层C/S架构:
增加了应用服务器。
将系统分为:数据层,应用逻辑层,表示层
B/S架构(是三层体系架构):
浏览器——web服务器——数据库服务器
相对灵活,但响应速度和动态交互性不如C/S
接口设计中的重要部分:
用户界面设计:三个准则:
- 用户控制系统
- 减少学习和记忆负担
- 保持界面的一致性
数据设计:
组件级别的数据设计,即设计供软件组件直接访问的数据结构。
低层的数据设计应推迟到后期进行。
注意信息的隐藏和耦合。
组件设计:
是接近代码层次的软件抽象描述。
- 结构化设计:基于过程
- 面向对象设计:基于类
部署设计:
包含了整个解决方案的逻辑架构和服务质量(QoS)需求。
项目审批发生在部署设计阶段,估计软件部署的成本,提交审批。
是一种高层架构,描述了逻辑环境到物理环境的映射。
四、结构化设计方法SD(Structured Design)
结构化设计中,软件的结构元素是模块,因此也称为模块设计。
接口设计:
- 内部接口:模块之间的接口。
- 外部接口:软件和硬件的接口,软件和其它软件的接口,软件和用户的交互界面。
SD数据设计的概括:将ER图转换为数据库表。
软件的结构分为:模块结构+数据结构。一般采用功能划分的方法进行软件结构设计,对整个问题进行分割,每一部分用一个或几个模块来完成。
模块的表示:
- 用矩形框表示,已定义的模块用双纵边矩形框表示。
模块的分类(实际系统中的模块属于以下任意一种,或某几种的组合):
- 传入模块
- 传出模块
- 变换模块
- 协调模块
模块的结构:
- 树状结构:
- 只有一个顶层(第0层)模块
- 上层模块调用下层模块,同一层模块之间互不调用
- 实际系统中建议使用树状结构,最底层可能存在公共模块,使得整个系统不是严格的树状结构,属正常情况
- 网状结构:
- 无法区分层次
- 任意模块可相互调用
- 系统结构复杂,难以处理
- 实际系统中不建议使用网状结构
用结构图表示模块结构:
菱形表示条件调用,圆弧表示循环调用。
理解深度,宽度(下图宽度为7),扇入,扇出:
数据结构:
基于数据流的设计方法是:过程驱动的设计方法。
数据流的类型:(一般都是以变换型为主,事务型为辅)
- 变换型数据流:工作过程大致分为3步:取得数据,变换数据,给出数据
变换型系统结构图如下:
- 事务型数据流:接受一项事务,分派适当的处理单元并给出结果。选择分派任务的部分称为事务(处理)中心或分派部件。调度模块如果不复杂,可以归入事务中心模块。
事务型系统结果图(简化):
变换型映射方法:将具有变换流特点的数据流图映射成软件结构:
自顶向下,设计下层模块的顺序是任意的。但一般先设计输入模块的下层模块。
一层一层往下分解。
事务型映射方法:将具有事务流特点的数据流图映射成软件结构:
变换型和事务型混合结构的例子:
模块的完善化:
模块完全相似,可能只是在数据类型上不一致。可以完全合并。
局部相似时,则不能将两者合并为一。一般的处理方法是将相似的部分分离出去。
模块的作用范围和控制范围:
模块的控制范围是指它本身和所有的从属模块。
模块的作用范围是指收模块内一个判定影响的范围。
模块的作用范围应该在模块的控制范围以内。
扇入和扇出:
适当的扇出数为2~5,最好不要超过9。扇出数过小会使结构图的深度增加,扇出数过大会使结构图的宽度增加。
一个好的软件模块设计,通常是:上层扇出较高,中层扇出较少,底层公用模块的扇入较高。
数据库设计:
数据库分为多种,其中关系数据库最成熟。多对多关系的映射需要引入关联表。
结构化程序设计用到的工具:
- 程序流程图
- N-S图(盒图)
- PAD图:采用PAD描述出来的程序一定是结构化程序,多少根竖线对应多少层
- 判定表:多重嵌套的条件选择
- 伪代码
五、面向对象的设计方法OOD(Object-Oriented Design)
OOA和OOD,分析和设计联系紧密,没有明显界限。
整个设计阶段的核心任务:创建包含操作的设计类图
从分析类到设计类:导出实体类,增加边界类,控制类
在OOD中,类和接口是程序的基本组成单元。
继承(子类对象继承父类的所有特征,又可以覆盖父类的方法)依赖性:
- 多态继承:
- 根据为请求服务的对象不同可以得到不同的行为。若在运行时对类进行实例化,称为动态绑定;若方法的调用是在编译时确定的,称为静态绑定。
- 多态不是伴随着继承产生。如果子类中不覆盖父类中的任何方法,就不会产生多态。
- 编译时继承依赖性:一般来说,所有的继承都会引入编译时依赖性。并且,依赖性是可传递的。
- 运行时继承依赖性
- 交互依赖性:通过消息连接产生的
- 无多态继承:
- 子类不覆盖父类的方法。
- 有时不是十分有用,但便于理解和管理。
- 扩展继承和约束继承:
- 扩展继承:子类继承了父类的属性,并提供额外属性来增强类的定义。
- 约束继承:子类对从父类继承来的方法和功能进行了约束和限制。
面向接口编程,而不是面向实现编程:接口依赖性又分为使用依赖性和实现依赖性。
在包之间增加新包,可以消除循环依赖性。
构件:比类更高级,包含一个或一组类,或者其它部署单元,完成一个或多个功能的特定服务。隐藏了具体的实现,只用接口对外提供服务。
从软件复用的角度,构件是指开发过程中可以复用的软件元素。具有独立性,不可拆分。
构件被实现为大粒度的单元,只能由一个实例。
OOD:系统划分为子系统。
封闭体系结构:每一层只能访问与其相邻的下一层。
开放体系结构:每一层可以访问比其下一层更低的层次。
典型的面向对象系统的分层结构:数据库层,业务逻辑层,用户界面层。
面向对象的设计顺序:业务逻辑层(问题域部分)M——人机交互部分V——C任务管理部分——数据管理部分。
数据管理部分:关联关系的映射: