【笔记】软件工程导论

【笔记】软件工程导论

第一章 软件工程学概述

1.1 软件危机

1.1.1 软件危机的介绍

软件危机是指在计算机软件的开发和维护过程中所遇到的一系列严重问题。

  1. 软件危机包括

    1. 如何开发软件,以满足对软件日益增长的需求

    2. 如何维护数量不断膨胀的已有软件

  2. 软件危机的典型表现

    1. 对软件开发成本和进度的估计常常很不准确

    2. 用户对“已完成的”软件系统不满意的现象经常发生

    3. 软件产品的质量往往靠不住

    4. 软件常常是不可维护的

    5. 软件通常没有适当的文档资料

    6. 软件成本在计算机系统总成本中所占的比例逐年上升

    7. 软件开发生产率提高的速度,远远跟不上计算机应用迅速普及深入的趋势

1.1.2 产生软件危机的原因

  1. 与软件本身的特点有关

  2. 软件开发与维护的方法不正确有关

1.1.3 消除软件危机的途径

  1. 彻底消除在计算机系统早期发展阶段形成的“软件就是程序”的错误观念

  2. 必须充分认识到软件开发不是某种个体劳动的神秘技巧,而应该是一种组织良好、管理严密、各类人员协同配合.共同完成的工程项目

  3. 应该推广使用在实践中总结出来的开发软件的成功的技术和方法,并且研究探索更好更有效的技术和方法

  4. 应该开发和使用更好的软件工具

1.2 软件工程

1.2.1 软件工程的介绍

软件工程是指导计算机软件开发和维护的一门工程学科

  1. 软件工程关注于大型程序的构造

  2. 软件工程的中心课题是控制复杂性

  3. 软件经常变化

  4. 开发软件的效率非常重要

  5. 和谐地合作是开发软件的关键

  6. 软件必须有效地支持它的用户

  7. 在软件工程领域中通常由具有一种文化背景的人替具有另一种文化背景的人创造产品

1.2.2 软件工程的基本原理

  1. 用分阶段的生命周期计划严格管理

  2. 坚持进行阶段评审

  3. 实行严格的产品控制

  4. 采用现代程序设计技术

  5. 结果应能清楚地审查

  6. 开发小组的人员应该少而精

  7. 承认不断改进软件工程实践的必要性

1.2.3 软件工程方法学

  1. 传统方法学:生命周期方法学或结构化范型

  2. 面向对象方法学

    1. 把对象作为融合了数据及在数据上的操作行为的统一的软件构件

    2. 把所有对象都划分成类

    3. 按照父类(或称为基类)与子类(或称为派生类)的关系,把若干个相关类组成一个层次结构的系统(也称为类等级)。

    4. 对象彼此间仅能通过发送消息互相联系。

1.3 软件生命周期

  1. 问题定义

  2. 可行性研究

  3. 需求分析

  4. 总体设计

  5. 详细设计

  6. 编码和单元测试

  7. 综合测试

  8. 软件维护

1.4 软件过程

1.4.1 瀑布模型


图1-4-1-1 传统的瀑布模型

  1. 阶段间具有顺序性和依赖性

阶段间具有顺序性和依赖性,这个特点有两重含义:①必须等前一阶段的工作完成之后,才能开始后阶段的工作;②前一阶段的输出文档就是后一阶段的输入文档,因此,只有前一阶段的输出文档正确,后一阶段的工作才能获得正确的结果。

  1. 推迟实现的观点

缺乏软件工程实践经验的软件开发人员,接到软件开发任务以后常常急于求成,总想尽早开始编写程序。

  1. 质量保证的观点

    1. 每个阶段都必须完成规定的文档,没有交出合格的文档就是没有完成该阶段的任务

    2. 每个阶段结束前都要对所完成的文档进行评审,以便尽早发现问题,改正错误。

在这里插入图片描述

图1-4-1-2 实际的瀑布模型

1.4.2 快速原型模型

在这里插入图片描述
图1-4-2-1 快速原型模型

1.4.3 增量模型

在这里插入图片描述
图1-4-3-1 增量模型
在这里插入图片描述

图1-4-3-2 风险更大的增量模型

1.4.4 螺旋模型

在这里插入图片描述

图1-4-4-1 简化的螺旋模型
在这里插入图片描述
图1-4-4-2 完整的螺旋模型

1.4.5 喷泉模型

在这里插入图片描述
图1-4-5-1 喷泉模型

1.4.6 Rational统一过程

  1. 最佳实践

    1. 迭代式开发

    2. 管理需求

    3. 使用基于构件的体系结构

    4. 可视化建模

    5. 验证软件质量

    6. 控制软件更变

  2. RUP软件开发生命周期

    1. 核心工作流

    2. 工作阶段

    3. RUP迭代式开发

1.4.7 敏捷过程与极限编程

  1. 敏捷过程

    1. 个体和交互胜过过程和工具

    2. 可以工作的软件胜过面面俱到的文档

    3. 客户合作胜过合同谈判

    4. 响应变化胜过遵循计划

  2. 极限编程

    1. 极限编程的有效实践

      1. 客户作为开发团队的成员

      2. 使用用户素材

      3. 短交付周期

      4. 验收测试

      5. 结对编程

      6. 测试驱动开发

      7. 集体所有

      8. 持续集成

      9. 可持续的开发速度

      10. 开放的工作空间

      11. 及时调整计划

      12. 简单的设计

      13. 重构

      14. 使用隐喻

    2. 极限编程的整体开发过程

在这里插入图片描述
图1-4-7-1 XP项目的整体开发过程

  1. 极限编程的迭代过程
    在这里插入图片描述
    图1-4-7-2 XP迭代开发过程

1.4.8 微软过程

  1. 微软过程准则

    1. 项目计划应该兼顾未来的不确定因素

    2. 用有效的风险管理来减少不确定因素的影响

    3. 经常生成并快速地测试软件的过渡版本,从而提高产品的稳定性和可预测性

    4. 采用快速循环、递进的开发过程

    5. 用创造性的工作来平衡产品特性和产品成本

    6. 项目进度表应该具有较高稳定性和权威性

    7. 使用小型项目组并发地完成开发工作

    8. 在项目早期把软件配置项基线化,项目后期则冻结产品

    9. 使用原型验证概念,对项目进行早期论证

    10. 把零缺陷作为追求的目标

    11. 里程碑评审会的目的是改进工作,切忌相互指责

  2. 微软软件生命周期
    在这里插入图片描述
    图1-4-8-1 微软软件生命周期阶段划分和主要里程碑

  3. 规划阶段

    1. 确定产品目标

      1. 获取竞争对手的信息

      2. 完成对客户和市场的调研分析

      3. 确定新版本产品应该具备的主要特性

      4. 确定相对于前一版本而言,新版本应该解决的问题和需要增加的功能

    2. 设计阶段

      1. 根据产品目标编写系统的特性规格说明书,这份规格说明书主要描述软件特性、系统结构、各构件间的相关性以及接口标准。

      2. 从系统高层开始着手进行系统设计,主要完成下述工作:简明扼要地描述整个系统的设计方案,绘制系统结构图,确定系统中存在的风险因素,分析系统的可重用性。

      3. 划分出系统中的子系统,给出各个子系统和各个构件的规格说明。

      4. 根据产品特性规格说明书制订产品开发计划。

    3. 开发阶段

    4. 稳定阶段

    5. 发布阶段

  4. 微软过程模型

第二章 可行性研究

2.1 可行性研究的任务

  1. 技术可行性

  2. 经济可行性

  3. 操作可行性

2.2 可行性研究过程

  1. 复查系统规模和目标

  2. 研究目前正在使用的系统

  3. 导出新系统的高层逻辑模型

  4. 进一步定义问题

  5. 导出和评价供选择的解法

  6. 推荐行动方针

  7. 草拟开发计划

  8. 书写文档提交审查

2.3 系统流程图

2.3.1 符号

在这里插入图片描述
图2-3-1-1 基本符号
在这里插入图片描述
图2-3-1-2 系统符号

2.3.2 例子

在这里插入图片描述
图2-3-2-1 库存清单系统的系统流程图

2.3.3 分层

面对复杂的系统时,一个比较好的方法是分层次地描绘这个系统。

2.4 数据流图

2.4.1 符号

在这里插入图片描述
图2-4-1-1 数据流图的符号

(a)基本符号的含义;(b)附加符号的含义

2.4.2 例子

2.4.3 命名

  1. 为数据流(或数据存储)命名

    1. 名字应代表整个数据流(或数据存储)的内容,而不是仅仅反映它的某些成分。

    2. 不要使用空洞的、缺乏具体含义的名字(如“数据”、“信息”、“输入”之类)。

    3. 如果在为某个数据流(或数据存储)起名字时遇到了困难,则很可能是因为对数据流图分解不恰当造成的,应该试试重新分解,看是否能克服这个困难。

  2. 为处理命名

    1. 通常先为数据流命名,然后再为与之相关联的处理命名。这样命名比较容易,而且体现了人类习惯的“由表及里”的思考过程。

    2. 名字应该反映整个处理的功能,而不是它的一部分功能。

    3. 名字最好由一个具体的及物动词加上一个具体的宾语组成。应该尽量避免使用“加工”、“处理”等空洞笼统的动词作名字。

    4. 通常名字中仅包括一个动词,如果必须用两个动词才能描述整个处理的功能,则把这个处理再分解成两个处理可能更恰当些。

    5. 如果在为某个处理命名时遇到困难,则很可能是发现了分解不当的迹象,应考虑重新分解。

2.4.4 用途

2.5 数据字典

2.5.1 数据字典的内容

  1. 数据流

  2. 数据流分量(即数据元素)

  3. 数据存储

  4. 处理

2.5.2 定义数据的方法

  1. 顺序:确定次序连接两个或多个分量

  2. 选择:两个或多个可能的元素中选取一个

  3. 重复:指定的分量重复零次或多次

  4. 可选:一个分量是可有可无的(重复零次或一次)

2.5.3 数据字典的用途

数据字典最重要的用途是作为分析阶段的工具。

2.5.4 数据字典的实现

  1. 名字

  2. 别名

  3. 描述

  4. 定义

  5. 位置

2.6 成本/效益分析

2.6.1 成本估计

  1. 代码行技术:代码行技术是比较简单的定量估算方法,它把开发每个软件功能的成本和实现这个功能需要用的源代码行数联系起来。

  2. 任务分解技术:这种方法首先把软件开发工程分解为若干个相对独立的任务。再分别估计每个单独的开发任务的成本,最后累加起来得出软件开发工程的总成本。

  3. 自动估计成本技术:采用自动估计成本的软件工具可以减轻人的劳动,并且使得估计的结果更客观。

2.6.2 成本/效益分析的方法

  1. 货币的时间价值:通常用利率的形式表示货币的时间价值

  2. 投资回收期:通常用投资回收期衡量一项开发工程的价值

  3. 纯收入:衡量工程价值的另一项经济指标是工程的纯收入,也就是在整个生命周期之内系统的累计经济效益(折合成现在值)与投资之差

  4. 投资回收率:把资金存入银行或贷给其他企业能够获得利息,通常用年利率衡量利息多少

第三章 需求分析

3.1 需求分析的任务

3.1.1 确定对系统的综合要求

  1. 功能需求:系统必须提供的服务

  2. 性能需求:系统必须满足的定时约束或容量约束,通常包括速度(响应时间)、信息量速率、主存容量、磁盘容量、安全性等方面的需求

  3. 可靠性和可用性需求:系统的可靠性

  4. 出错处理需求:系统对环境错误应该怎样响应

  5. 接口需求:系统与它的环境通信的格式

  6. 约束:设计约束或实现约束描述在设计或实现应用系统时应遵守的限制条件

  7. 逆向需求:说明软件系统不应该做什么

  8. 将来可能提出的要求:应该明确地列出那些虽然不属于当前系统开发范畴,但是据分析将来很可能会提出来的要求。

3.1.2 分析系统的数据要求

任何一个软件系统本质上都是信息处理系统,系统必须处理的信息和系统应该产生的信息在很大程度上决定了系统的面貌,对软件设计有深远影响,因此,必须分析系统的数据要求,这是软件需求分析的一个重要任务。
复杂的数据由许多基本的数据元素组成,数据结构表示数据元素之间的逻辑关系。利用数据字典可以全面准确地定义数据,但是数据字典的缺点是不够形象直观。为了提高可理解性,常常利用图形工具辅助描绘数据结构。

3.1.3 到处系统的逻辑模型

综合上述两项分析的结果可以导出系统的详细的逻辑模型,通常用数据流图、实体联系图、状态转换图、数据字典和主要的处理算法描述这个逻辑模型。

3.1.4 修正系统开发计划

根据在分析过程中获得的对系统的更深入更具体的了解,可以比较准确地估计系统的成本和进度,修正以前制定的开发计划。

3.2 与用户沟通获取需求的方法

3.2.1 访谈

  1. 正式访谈

  2. 非正式访谈

  3. 情景分析

3.2.2 面向数据流自顶向下求精

在这里插入图片描述
图3-2-2 面向数据流自顶向下求精过程

3.2.3 简易的应用规格说明技术

简易的应用规格说明技术是为了解决使用传统的访谈或面向数据流自顶向下求精方法定义需求时,用户处于被动地位而且往往有意无意地与开发者区分“彼此”。

3.2.4 快速建立软件模型

  1. 第四代技术

  2. 可重用的软件构件

  3. 形式化规格说明和原型环境

3.3 分析建模与规格说明

3.3.1 分析建模

模型,就是为了理解事物而对事物作出的一种抽象,是对事物的一种无歧义的书面描述。

3.3.2 软件需求规格说明

软件需求规格说明是需求分析阶段得出的最主要的文档。

3.4 实体-联系图

3.4.1 数据对象

  1. 数据对象是对软件必须理解的复合信息的抽象

  2. 数据对象可以是外部实体(例如产生或使用信息的任何事物)、事物(例如报表)、行为(例如打电话)、事件(例如响警报)、角色(例如教师、学生)、单位(例如会计科)、地点(例如仓库)或结构(例如文件)等

3.4.2 属性

  1. 属性定义了数据对象的性质

  2. 应该根据对所要解决的问题的理解,来确定特定数据对象的一组合适的属性

3.4.3 联系

  1. 一对一联系(1:1)

  2. 一对多联系(1:N)

  3. 多对多联系(M:N)

3.4.4 实体-联系图的符号

使用实体-联系图来建立数据模型。可以把实体-联系图简称为ER图,相应地可把用ER图描绘的数据模型称为ER模型。

3.5 数据规范化

  1. 第一范式:每个属性值都必须是原子值,即仅仅是一个简单值而不含内部结构

  2. 第二范式:满足第一范式条件,而且每个非关键字属性都由整个关键字决定(而不是由关键字的一部分来决定)

  3. 第三范式:符合第二范式的条件,每个非关键字属性都仅由关键字决定,而且一个非关键字属性不能仅仅是对另一个非关键字属性的进–步描述(即一个非关键字属性值不依赖于另一个非关键字属性值)

3.6 状态转换图

3.6.1 状态

状态是任何可以被观察到的系统行为模式,一个状态代表系统的一种行为模式。

  1. 初态(初始状态)-只能有一个

  2. 终态(最终状态)-可以有0个至多个

  3. 中间状态

3.6.2 事件

事件是在某个特定时刻发生的事情,它是对引起系统做动作或(和)从一个状态转换到另一个状态的外界事件的抽象。

3.6.3 符号

  1. 在状态图中,初态用实心圆表示,终态用一对同心圆(内圆为实心圆)表示。

  2. 中间状态用圆角矩形表示,可以用两条水平横线把它分成上、中、下3个部分。

在这里插入图片描述
图3-6-3-1 状态图中使用的主要符号

3.6.4 例子

在这里插入图片描述
图3-6-4-1 电话系统的状态图

3.7 其他图形工具

3.7.1 层次方框图

层次方框图用树形结构的一系列多层次的矩形框描绘数据的层次结构。
在这里插入图片描述
图3-7-1-1 层次方框图的一个例子

3.7.2 Warnier图

在这里插入图片描述
图3-7-2-1 Warnier图的一个例子

3.7.3 IPO图

在这里插入图片描述
图3-7-3-1 IPO图的一个例子
在这里插入图片描述
图3-7-3-2 改进的IPO图的形式

3.8 验证软件需求

3.8.1 从哪些方面验证软件需求的正确性

  1. 一致性:所有需求必须是一致的,任何一条需求不能和其他需求互相矛盾

  2. 完整性:需求必须是完整的,规格说明书应该包括用户需要的每一个功能或性能

  3. 现实性:指定的需求应该是用现有的硬件技术和软件技术基本上可以实现的

  4. 有效性:必须证明需求是正确有效的,确实能解决用户面对的问题

3.8.2 验证软件需求的方法

  1. 验证需求的一致性

  2. 验证需求的现实性

  3. 验证需求的完整性和有效性

3.8.3 用于需求分析的软件工具

  1. 用于需求分析的软件工具应满足的要求

    1. 必须有形式化的语法(或表),因此可以用计算机自动处理使用这种语法说明的内容

    2. 使用这个软件工具能够导出详细的文档

    3. 必须提供分析(测试)规格说明书的不一致性和冗余性的手段,并且应该能够产生一组报告指明对完整性分析的结果

    4. 使用这个软件工具之后,应该能够改进通信状况

  2. PSL/PSA系统的主要功能

    1. 描述任何应用领域的信息系统

    2. 创建一个数据库保存对该信息系统的描述符

    3. 对描述符施加增加、删除和更改等操作

    4. 产生格式化的文档和关于规格说明书的各种分析报告

第四章 形式化说明技术

4.1 概述

4.1.1 非形式化方式的缺点

  1. 矛盾是指一组相互冲突的陈述
  2. 二义性是指读者可以用不同方式理解的陈述
  3. 含糊性
  4. 不完整性
  5. 抽象层次混乱是指在非常抽象的陈述中混进了一些关于细节的低层次陈述

4.1.2 形式化方法的优点

为了克服非形式化方法的缺点,人们把数学引入软件开发过程,创造了基于数学的形式化方法。

  1. 数学能够简洁准确地描述物理现象、对象或动作的结果,因此是理想的建模工具二义性是指读者可以用不同方式理解的陈述
  2. 数学以在不同的软件工程活动之间平滑地过渡
  3. 数学提供了高层确认的手段

4.1.3 应用形式化方法的准则

  1. 应该选用适当的表示方法

  2. 应该形式化,但不要过分形式化

  3. 应该估算成本

  4. 应该有形式化方法顾问随时提供咨询

  5. 不应该放弃传统的开发方法

  6. 应该建立详尽的文档

  7. 不应该放弃质量标准

  8. 应该测试、测试再测试

  9. 应该重用

4.2 有穷状态机

4.2.1 概念

一个有穷状态机包括下述5个部分:状态集J、输入集K、由当前状态和当前输入确定下一个状态(次态)的转换函数T、初始态S和终态集F。

4.2.2 例子

4.2.3 评价

当前状态+事件+谓词→下个状态

4.3 Petri网

4.3.1 概念

并发系统中遇到的一个主要问题是定时问题。这个问题可以表现为多种形式,如同步问题、竞争条件以及死锁问题。用于确定系统中隐含的定时问题的一种有效技术是Petri网,这种技术的一个很大的优点是它也可以用于设计中。

4.3.2 例子

  1. 电梯按钮

  2. 楼层按钮

4.4 Z语言

4.4.1 简介

  1. 给定的集合:一个Z规格说明从一系列给定的初始化集合开始。所谓初始化集合就是不需要详细定义的集合,这种集合用带方括号的形式表示

  2. 状态定义:一个Z规格说明由若干个“格(schema)”组成,每个格含有一组变量说明和一系列限定变量取值范围的谓词

  3. 初始状态:抽象的初始状态是指系统第一次开启时的状态

  4. 操作:如果一个原来处于关闭状态的按钮被按下,则该按钮开启,这个按钮就被添加到pushed集中

4.4.2 评价

  1. 可以比较容易地发现用Z写的规格说明的错误,特别是在自己审查规格说明,及根据形式化的规格说明来审查设计与代码时,情况更是如此。

  2. 用Z写规格说明时,要求作者十分精确地使用Z说明符。

  3. Z是一种形式化语言,在需要时开发者可以严格地验证规格说明的正确性。

  4. 虽然完全学会Z语言相当困难,但是,经验表明,只学过中学数学的软件开发人员仍然可以只用比较短的时间就学会编写Z规格说明。

  5. 使用Z语言可以降低软件开发费用。

  6. 虽然用户无法理解用Z写的规格说明,但是,可以依据Z规格说明用自然语言重写规格说明。

第五章 总体设计

5.1 设计过程

  1. 设想供选择的方案:在总体设计阶段分析员应该考虑各种可能的实现方案,并且力求从中选出最佳方案。

  2. 选取合理的方案:应该从前一步得到的一系列供选择的方案中选取若干个合理的方案,通常至少选取低成本、中等成本和高成本的3种方案。

    1. 系统流程图

    2. 组成系统的物理元素清单

    3. 成本/效益分析

    4. 实现这个系统的进度计划

  3. 推荐最佳方案:分析员应该综合分析对比各种合理方案的利弊,推荐一个最佳的方案,并且为推荐的方案制定详细的实现计划。

  4. 功能分解:为了最终实现目标系统,必须设计出组成这个系统的所有程序和文件(或数据库)

  5. 设计软件结构:通常程序中的一个模块完成一个适当的子功能。

  6. 设计数据库:对于需要使用数据库的那些应用系统,软件工程师应该在需求分析阶段所确定的系统数据需求的基础上,进一步设计数据库。

  7. 制定测试计划:在软件开发的早期阶段考虑测试问题,能促使软件设计人员在设计时注意提高软件的可测试性。

  8. 书写文档

    1. 系统说明

    2. 用户手册

    3. 测试计划

    4. 详细的实现计划

    5. 数据库设计结果

  9. 审查和复审:最后应该对总体设计的结果进行严格的技术审查,在技术审查通过之后再由客户从管理角度进行复审。

5.2 设计原理

5.2.1 模块化

模块是由边界元素限定的相邻程序元素(例如,数据说明,可执行的语句)的序列,而且有一个总体标识符代表它。模块是构成程序的基本构件。
模块化就是把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能,把这些模块集成起来构成一个整体,可以完成指定的功能满足用户的需求。

5.2.2 抽象

人类在认识复杂现象的过程中使用的最强有力的思维工具是抽象。人们在实践中认识到,在现实世界中一定事物、状态或过程之间总存在着某些相似的方面(共性)。把这些相似的方面集中和概括起来,暂时忽略它们之间的差异,这就是抽象。或者说抽象就是抽出事物的本质特性而暂时不考虑它们的细节。

5.2.3 逐步求精

逐步求精定义为为了能集中精力解决主要问题而尽量推迟对问题细节的考虑。

5.2.4 信息隐藏和局部化

信息隐藏原理:应该这样设计和确定模块,使得一个模块内包含的信息(过程和数据)对于不需要这些信息的模块来说,是不能访问的。
局部化是指把一些关系密切的软件元素物理地放得彼此靠近。

5.2.5 模块独立

  1. 耦合:对一个软件结构内不同模块之间互连程度的度量
  1. 数据耦合:两个模块彼此间通过参数交换信息,而且交换的信息仅仅是数据,那么这种耦合称为数据耦合。数据耦合是低耦合。
  2. 控制耦合:传递的信息中有控制信息(尽管有时这种控制信息以数据的形式出现),则这种耦合称为控制耦合。控制耦合是中等程度的耦合。
  3. 特征耦合:当把整个数据结构作为参数传递而被调用的模块只需要使用其中一部分数据元素时,就出现了特征耦合。
  4. 公共环境耦合:当两个或多个模块通过一个公共数据环境相互作用时,它们之间的耦合称为公共环境耦合。
  5. 内容耦合:最高程度的耦合是内容耦合。
    a) 一个模块访问另一个模块的内部数据。
    b) 一个模块不通过正常入口而转到另-一个模块的内部。
    c) 两个模块有一部分程序代码重叠(只可能出现在汇编程序中)。
    d) 一个模块有多个入口(这意味着一个模块有几种功能)。
  1. 内聚:标志着一个模块内各个元素彼此结合的紧密程度,它是信息隐藏和局部化概念的自然扩展
  1. 低内聚
    a) 一个模块完成一组任务,这些任务彼此间即使有关系,关系也是很松散的,就叫做偶然内聚。
    b) 一个模块完成的任务在逻辑上属于相同或相似的一类,则称为逻辑内聚。
    c) 一个模块包含的任务必须在同一段时间内执行,就叫时间内聚。
  2. 中内聚
    a) 一个模块内的处理元素是相关的,而且必须以特定次序执行,则称为过程内聚。
    b) 模块中所有元素都使用同一个输入数据和(或)产生同一个输出数据,则称为通信内聚。
  3. 高内聚
    a) 一个模块内的处理元素和同一个功能密切相关,而且这些处理必须顺序执行(通常–个处理元素的输出数据作为下一个处理元素的输入数据),则称为顺序内聚。
    b) 模块内所有处理元素属于一个整体,完成一个单一的功能,则称为功能内聚。功能内聚是最高程度的内聚。

5.3 启发规则

  1. 改进软件结构提高模块独立性

  2. 模块规模应该适中

  3. 深度、宽度、扇出和扇入都应适当

  4. 模块的作用域应该在控制域之内

  5. 力争降低模块接口的复杂程度

  6. 设计单入口单出口的模块

  7. 模块功能应该可以预测

5.4 描绘软件结果的图形工具

5.4.1 层次图和HIPO图

在这里插入图片描述
图5-4-1-1 正文加工系统的层次图
在这里插入图片描述
图5-4-1-2 带编号的层次图(H图)

5.4.2 结构图

在结构图中通常还用带注释的箭头表示模块调用过程中来回传递的信息。如果希望进一步标明传递的信息是数据还是控制信息,则可以利用注释箭头尾部的形状来区分:尾部是空心圆表示传递的是数据,实心圆表示传递的是控制信息。
在这里插入图片描述
图5-4-2-1 结构图的例子——产生最佳解的一般结构

5.5 面向数据流的设计方法

5.5.1 概念

  1. 变换流:根据基本系统模型,信息通常以“外部世界”的形式进入软件系统,经过处理以后再以“外部世界”的形式离开系统。
    在这里插入图片描述
    图5-5-1-1 变换流
    在这里插入图片描述
    图5-5-1-2 事务流

  2. 事务流:基本系统模型意味着变换流,因此,原则上所有信息流都可以归结为这一类。

    1. 接收输入数据(输入数据又称为事务)。

    2. 分析每个事务以确定它的类型。

    3. 根据事务类型选取一条活动通路。

  3. 设计过程
    在这里插入图片描述
    图5-5-1-3 面向数据流方法的设计过程

5.5.2 变换分析

  1. 例子

  2. 设计步骤

    1. 复查基本系统模型:复查的目的是确保系统的输入数据和输出数据符合实际

    2. 复查并精化数据流图:应该对需求分析阶段得出的数据流图认真复查,并且在必要时进行精化

    3. 确定数据流图具有变换特性还是事务特性:当遇到有明显事务特性的信息流时,建议采用事务分析方法进行设计。

    4. 确定输入流和输出流的边界,从而孤立出变换中心:不同设计人员可能会在流内选取稍微不同的点作为边界的位置

    5. 完成“第一级分解”

    6. 完成“第二级分解”

    7. 使用设计度量和启发式规则对第一次分割得到的软件结构进一步精化:对第一次分割得到的软件结构,总可以根据模块独立原理进行精化。

5.5.3 事务分析

5.5.4 设计优化

第六章 详细设计

6.1 结构程序设计

结构程序设计经典定义:如果一个程序的代码块仅仅通过顺序、选择和循环这3种基本控制结构进行连接,并且每个代码块只有一个入口和一个出口,则称这个程序是结构化的。

6.2 人机界面设计

6.2.1 设计问题

  1. 系统响应时间:从用户完成某个控制动作(例如按回车键或单击鼠标),到软件给出预期的响应(输出信息或做动作)之间的这段时间。

  2. 用户帮助设施

    1. 在用户与系统交互期间,是否在任何时候都能获得关于系统任何功能的帮助信息?

      1. 提供部分功能的帮助信息

      2. 提供全部功能的帮助信息

    2. 用户怎样请求帮助?

      1. 帮助菜单

      2. 特殊功能键

      3. HELP命令

    3. 怎样显示帮助信息?

      1. 在独立的窗口中

      2. 指出参考某个文档(不理想)

      3. 在屏幕固定位置显示简短提示

    4. 用户怎样返回到正常的交互方式中?

      1. 屏幕上的返回按钮

      2. 功能键

    5. 怎样组织帮助信息?

      1. 平面结构(所有信息都通过关键字访问)

      2. 信息的层次结构(用户可在该结构中查到更详细的信息)

      3. 超文本结构

  3. 出错信息处理

    1. 信息应该用用户可以理解的术语描述问题

    2. 信息应该提供有助于从错误中恢复的建设性意见

    3. 信息应该指出错误可能导致哪些负面后果(例如,破坏数据文件),以便用户检查是否出现了这些问题,并在确实出现问题时及时解决

    4. 信息应该伴随着听觉上或视觉上的提示,例如,在显示信息时同时发出警告铃声,或者信息用闪烁方式显示,或者信息用明显表示出错的颜色显示

    5. 信息不能带有指责色彩,也就是说,不能责怪用户

  4. 命令交互

    1. 是否每个菜单选项都有对应的命令?

    2. 采用何种命令形式?

      1. 控制序列(例如,Ctrl+P)

      2. 功能键

      3. 输入命令

    3. 学习和记忆命令的难度有多大?忘记了命令怎么办?

    4. 用户是否可以定制或缩写命令?

6.2.2 设计过程

  1. 系统及其界面的规格说明书的长度和复杂程度,预示了用户学习使用该系统所需要的工作量。

  2. 命令或动作的数量、命令的平均参数个数或动作中单个操作的个数,预示了系统的交互时间和总体效率。

  3. 设计模型中包含的动作,命令和系统状态的数量,预示了用户学习使用该系统时需要记忆的内容的多少。

  4. 界面风格、帮助设施和出错处理协议,预示了界面的复杂程度及用户接受该界面的程度。

6.2.3 人机界面设计指南

  1. 一般交互指南

    1. 保持一致性

    2. 提供有意义的反馈

    3. 在执行有较大破坏性的动作之前要求用户确认

    4. 允许取消绝大多数操作

    5. 减少在两次操作之间必须记忆的信息量

    6. 提高对话、移动和思考的效率

    7. 允许犯错误

    8. 按功能对动作分类,并据此设计屏幕布局

    9. 提供对用户工作内容敏感的帮助设施

    10. 用简单动词或动词短语作为命令名

  2. 信息显示指南

    1. 只显示与当前工作内容有关的信息

    2. 不要用数据淹没用户,应该用便于用户迅速吸取信息的方式来表示数据

    3. 使用一致的标记、标准的缩写和可预知的颜色

    4. 允许用户保持可视化的语境

    5. 产生有意义的出错信息

    6. 使用大小写、缩进和文本分组以帮助理解

    7. 使用窗口分隔不同类型的信息。

    8. 使用“模拟”显示方式表示信息,以使信息更容易被用户提取。

    9. 高效率地使用显示屏。

  3. 数据输入指南

    1. 尽量减少用户的输入动作

    2. 保持信息显示和数据输入之间的一致性

    3. 允许用户自定义输入

    4. 交互应该是灵活的,并且可调整成用户最喜欢的输入方式

    5. 使在当前动作语境中不适用的命令不起作用

    6. 让用户控制交互流

    7. 对所有输入动作都提供帮助

    8. 消除冗余的输入

6.3 过程设计的工具

6.3.1 程序流程图

程序流程图的主要缺点

  1. 程序流程图本质上不是逐步求精的好工具,它诱使程序员过早地考虑程序的控制流程,而不去考虑程序的全局结构

  2. 程序流程图中用箭头代表控制流,因此程序员不受任何约束,可以完全不顾结构程序设计的精神,随意转移控制

  3. 程序流程图不易表示数据结构
    在这里插入图片描述
    图6-3-1-1 程序流程图中使用的符号

(a)选择(分支);(b)注释;©预先定义的处理;(d)多分支;(e)开始或停止;(f)准备;(g)循环上界限;(h)循环下界限;(i)虚线;(j)省略符;(k)并行方式;(1)处理;(m)输入输出;(n)连接;(o)换页连接;§控制流

6.3.2 盒图

  1. 功能域(即一个特定控制结构的作用域)明确,可以从盒图上一眼就看出来

  2. 不可能任意转移控制

  3. 很容易确定局部和全程数据的作用域

  4. 很容易表现嵌套关系,也可以表示模块的层次结构
    在这里插入图片描述
    图6-3-2-1 盒图的基本符号

(a)顺序;(b)IF_THEN_ELSE型分支;©CASE型多分支;(d)循环;(e)调用子程序A

6.3.3 PAD图

在这里插入图片描述
图6-3-3-1 PAD图的基本符号

(a)顺序(先执行P1后执行P2);(b)选择(1F C THEN P1 ELSE
P2);©CASE型多分支;(d)WHILE型循环(WHILE CDO P);(e)UNTIL型循环(REPEAT P UNTIL
C);(f)语句标号;(g)定义

PAD图的主要优点

  1. 使用表示结构化控制结构的PAD符号所设计出来的程序必然是结构化程序。

  2. PAD图所描绘的程序结构十分清晰

  3. 用PAD图表现程序逻辑,易读、易懂、易记

  4. 容易将PAD图转换成高级语言源程序,这种转换可用软件工具自动完成,从而可省去人工编码的工作,有利于提高软件可靠性和软件生产率

  5. 即可用于表示程序逻辑,也可用于描绘数据结构

  6. PAD图的符号支持自顶向下、逐步求精方法的使用

在这里插入图片描述
图6-3-3-2 使用PAD图提供的定义功能来逐步求精的例子

(a)初始的PAD图;(b)使用def符号细化处理框P2

6.3.4 判定表

一张判定表由4部分组成,左上部列出所有条件,左下部是所有可能做的动作,右上部是表示各种条件组合的一个矩阵,右下部是和每种条件组合相对应的动作。判定表右半部的每一列实质上是一条规则,规定了与特定的条件组合相对应的动作。

例:

表6-3-4-1 用判定表表示计算行李费的算法
在这里插入图片描述

6.3.5 判定树

判定树是判定表的变种,它也能清晰地表示复杂的条件组合与应做的动作之间的对应关系。判定树的优点在于,它的形式简单到不需任何说明,一眼就可以看出其含义,因此易于掌握和使用。

例:
在这里插入图片描述
图6-3-5-1 用判定树表示计算行李费的算法

6.3.6 过程设计语言(PDL)

  1. PDL特点

    1. 关键字的固定语法,它提供了结构化控制结构、数据说明和模块化的特点

    2. 自然语言的自由语法,它描述处理特点

    3. 数据说明的手段

    4. 模块定义和调用的技术,应该提供各种接口描述模式

  2. PDL优点

    1. 可以作为注释直接插在源程序中间

    2. 可以使用普通的正文编辑程序或文字处理系统,很方便地完成PDL的书写和编辑工作

    3. 已经有自动处理PDL的程序存在,而且可以自动由PDL生成程序代码

6.4 面向数据结构的设计方法

6.4.1 Jackson图

  1. 顺序结构:顺序结构的数据由一个或多个数据元素组成,每个元素按确定次序出现一次

在这里插入图片描述
图6-4-1-1 A由B、C、D3个元素顺序组成

(每个元素只出现一次,出现的次序依次是B、C和D)

  1. 选择结构:选择结构的数据包含两个或多个数据元素,每次使用这个数据时按一定条件从这些数据元素中选择一个

在这里插入图片描述
图6-4-1-2 根据条件A是B或C或D中的某一个

(注意,在B、C和D的右上角有小圆圈做标记)

  1. 重复结构:重复结构的数据,根据使用时的条件由一个数据元素出现零次或多次构成
    在这里插入图片描述
    图6-4-1-3 A由B出现N次(N≥0)组成
    (注意,在B的右上角有星号标记)

6.4.2 改进的Jackson图

在这里插入图片描述
图6-4-2-1 改进的Jackson图

(a)顺序结构,B、C,D中任一个都不能是选择出现或重复出现的数据元素(即不能是右上角有小圆圈或星号标记的元素)

(b)选择结构,S右面括号中的数字i是分支条件的编号

©可选结构,A或者是元素B或者不出现(可选结构是选择结构的一-种常见的特殊形式)

(d)重复结构,循环结束条件的编号为i

6.4.3 Jackson方法

  1. 分析并确定输入数据和输出数据的逻辑结构,并用Jackson图描绘这些数据结构

  2. 找出输入数据结构和输出数据结构中有对应关系的数据单元

  3. 用下述3条规则从描绘数据结构的Jackson图导出描绘程序结构的Jackson图

    1. 为每对有对应关系的数据单元,按照它们在数据结构图中的层次在程序结构图的相应层次画一个处理框(注意,如果这对数据单元在输入数据结构和输出数据结构中所处的层次不同,则和它们对应的处理框在程序结构图中所处的层次与它们之中在数据结构图中层次低的那个对应)

    2. 根据输入数据结构中剩余的每个数据单元所处的层次,在程序结构图的相应层次分别为它们画上对应的处理框

    3. 根据输出数据结构中剩余的每个数据单元所处的层次,在程序结构图的相应层次分别为它们画上对应的处理框

  4. 列出所有操作和条件(包括分支条件和循环结束条件),并且把它们分配到程序结构图的适当位置

  5. 用伪码表示程序

6.5 程序复杂程度的定量度量

6.5.1 McCabe方法

  1. 流图
    在这里插入图片描述
    图6-5-1-1 把程序流程图映射成流图

(a)程序流程图;(b)流图

  1. 计算环形复杂度的方法

    1. 流图中线性无关的区域数等于环形复杂度。

    2. 流图G的环形复杂度V(G)=E-N+2,其中,E是流图中边的条数,N是结点数。

    3. 流图G的环形复杂度V(G)=P+1,其中,P是流图中判定结点的数目。
      在这里插入图片描述
      图6-5-1-2 由PDL翻译成的流图(环形复杂度为4)

  2. 环形复杂度的用途

程序的环形复杂度取决于程序控制流的复杂程度,即取决于程序结构的复杂程度。

6.5.2 Halstead方法

根据程序中运算符和操作数的总数来度量程序的复杂程度。令N1为程序中运算符出现的总次数,N2为操作数出现的总次数,程序长度N定义为:N=N1+N2

第七章 实现

7.1 编码

7.1.1 选择程序设计语言

  1. 系统用户的要求

  2. 可以使用的编译程序

  3. 可以得到的软件工具

  4. 工程规模

  5. 程序员的知识

  6. 软件可移植性要求

  7. 软件的应用领域

7.1.2 编码风格

  1. 程序内部的文档:包括恰当的标识符、适当的注解和程序的视觉组织等

  2. 数据说明:数据说明的次序应该标准化(例如按照数据结构或数据类型确定说明的次序)

  3. 语句构造:设计期间确定了软件的逻辑结构,然而个别语句的构造却是编写程序的一个主要任务。

    1. 不要为了节省空间而把多个语句写在同一行

    2. 尽量避免复杂的条件测试

    3. 尽量减少对“非”条件的测试

    4. 避免大量使用循环嵌套和条件嵌套

    5. 利用括号使逻辑表达式或算术表达式的运算次序清晰直观

  4. 输入输出

    1. 对所有输入数据都进行检验

    2. 检查输入项重要组合的合法性

    3. 保持输入格式简单

    4. 使用数据结束标记,不要要求用户指定数据的数目

    5. 明确提示交互式输入的请求,详细说明可用的选择或边界数值

    6. 当程序设计语言对格式有严格要求时,应保持输入格式一致

    7. 设计良好的输出报表

    8. 给所有输出数据加标志

  5. 效率

    1. 运行时间

      1. 写程序之前先简化算术的和逻辑的表达式

      2. 仔细研究嵌套的循环,以确定是否有语句可以从内层往外移

      3. 尽量避免使用多维数组

      4. 尽量避免使用指针和复杂的表

      5. 使用执行时间短的算术运算

      6. 不要混合使用不同的数据类型

      7. 尽量使用整数运算和布尔表达式

    2. 存储效率

    3. 输入输出效率

      1. 所有输入输出都应该有缓冲,以减少用于通信的额外开销

      2. 对二级存储器(如磁盘)应选用最简单的访问方法

      3. 二级存储器的输入输出应该以信息组为单位进行

      4. 如果“超高效的”输入输出很难被人理解,则不应采用这种方法

7.2 软件测试基础

7.2.1 软件测试的目标

  1. 测试是为了发现程序中的错误而执行程序的过程

  2. 好的测试方案是极可能发现迄今为止尚未发现的错误的测试方案

  3. 成功的测试是发现了至今为止尚未发现的错误的测试

7.2.2 软件测试准则

  1. 所有测试都应该能追溯到用户需求

  2. 应该远在测试开始之前就制定出测试计划

  3. 把Pareto原理应用到软件测试中

  4. 应该从“小规模”测试开始,并逐步进行“大规模”测试

  5. 穷举测试是不可能的

  6. 为了达到最佳的测试效果,应该由独立的第三方从事测试工作

7.2.3 测试方式

  1. 黑盒测试:把程序看作一个黑盒子,完全不考虑程序的内部结构和处理过程。
  2. 白盒测试:把程序看成装在一个透明的白盒子里,测试者完全知道程序的结构和处理算法。

7.2.4 测试步骤

  1. 模块测试:在设计得好的软件系统中,每个模块完成一个清晰定义的子功能,而且这个子功能和同级其他模块的功能之间没有相互依赖关系

  2. 子系统测试:子系统测试是把经过单元测试的模块放在一起形成一个子系统来测试

  3. 系统测试:系统测试是把经过测试的子系统装配成一个完整的系统来测试

  4. 验收测试:验收测试把软件系统作为单一的实体进行测试,测试内容与系统测试基本类似,但是它是在用户积极参与下进行的,而且可能主要使用实际数据(系统将来要处理的信息)进行测试

  5. 平行测试

    1. 可以在准生产环境中运行新系统而又不冒风险

    2. 用户能有一段熟悉新系统的时间

    3. 可以验证用户指南和使用手册之类的文档

    4. 能够以准生产模式对新系统进行全负荷测试,可以用测试结果验证性能指标

7.2.5 测试阶段的信息流

  1. 软件配置:需求说明书、设计说明书和源程序清单等

  2. 测试配置:测试计划和测试方案
    在这里插入图片描述
    图7-2-5-1 测试阶段的信息流

7.3 单元测试

7.3.1 测试重点

  1. 模块接口:首先应该对通过模块接口的数据流进行测试,如果数据不能正确地进出,所有其他测试都是不切实际的

    1. 参数的数目、次序、属性或单位系统与变元是否一致

    2. 是否修改了只作输入用的变元

    3. 全局变量的定义和用法在各个模块中是否一致

  2. 局部数据结构:局部数据说明、初始化、默认值等方面

  3. 重要的执行通路

  4. 出错处理通路

    1. 对错误的描述是难以理解的

    2. 记下的错误与实际遇到的错误不同

    3. 在对错误进行处理之前,错误条件已经引起系统干预

    4. 对错误的处理不正确

    5. 描述错误的信息不足以帮助确定造成错误的位置

  5. 边界条件

7.3.2 代码审查

  1. 组长,应该是一个很有能力的程序员,而且没有直接参与这项工程
  2. 程序的设计者
  3. 程序的编写者
  4. 程序的测试者

7.3.3 计算机测试

模块不是一个独立的程序,因此必须为每个单元测试开发驱动软件和(或)存根软件
驱动程序是一个“主程序”,它接收测试数据,把这些数据传送给被测试的模块,并且印出有关的结果

7.4 集成测试

7.4.1 自顶向下集成

  1. 对主控制模块进行测试,测试时用存根程序代替所有直接附属于主控制模块的模块

  2. 根据选定的结合策略(深度优先或宽度优先),每次用一个实际模块代换一个存根程序(新结合进来的模块往往又需要新的存根程序)

  3. 在结合进一个模块的同时进行测试

  4. 为了保证加入模块没有引进新的错误,可能需要进行回归测试(即全部或部分地重复以前做过的测试)。

  5. 从②开始不断地重复进行上述过程,直到构造起完整的软件结构为止。
    在这里插入图片描述
    图7-4-1-1 自顶向下结合

7.4.2 自底向上集成

  1. 把低层模块组合成实现某个特定的软件子功能的族

  2. 写一个驱动程序(用于测试的控制程序),协调测试数据的输入和输出

  3. 对由模块组成的子功能族进行测试

  4. 去掉驱动程序,沿软件结构自下向上移动,把子功能族组合起来形成更大的子功能族

  5. 上述第②~④步实质上构成了一个循环

在这里插入图片描述
图7-4-2-1 自底向上结合

7.4.3 不同集成测试策略的比较

  1. 改进的自顶向下测试方法。基本上使用自顶向下的测试方法,但是在早期使用自底向上的方法测试软件中的少数关键模块。一般的自顶向下方法所具有的优点在这种方法中也都有,而且能在测试的早期发现关键模块中的错误;但是,它的缺点也比自顶向下方法多一条,即测试关键模块时需要驱动程序。

  2. 混合法。对软件结构中较上层使用的自顶向下方法与对软件结构中较下层使用的自底向上方法相结合。这种方法兼有两种方法的优点和缺点,当被测试的软件中关键模块比较多时,这种混合法可能是最好的折衷方法。

7.4.4 回归测试

  1. 检测软件全部功能的代表性测试用例

  2. 专门针对可能受修改影响的软件功能的附加测试

  3. 针对被修改过的软件成分的测试

7.5 确认测试

7.5.1 确认测试的范围

  1. 功能和性能与用户要求一致,软件是可以接受的

  2. 功能和性能与用户要求有差距

7.5.2 软件配置复查

确认测试的一个重要内容是复查软件配置。复查的目的是保证软件配置的所有成分都齐全,质量符合要求,文档与程序完全一致,具有完成软件维护所必须的细节,而且已经编好目录。

7.5.3 Alpha和Beta测试

  1. Alpha测试由用户在开发者的场所进行,并且在开发者对用户的“指导”下进行测试。

  2. Beta测试由软件的最终用户们在一个或多个客户场所进行。

7.6 白盒测试技术

7.6.1 逻辑覆盖

  1. 语句覆盖:为了暴露程序中的错误,至少每个语句应该执行一次

  2. 判定覆盖:判定覆盖又叫分支覆盖,它的含义是,不仅每个语句必须至少执行一次,而且每个判定的每种可能的结果都应该至少执行一次,也就是每个判定的每个分支都至少执行一次

  3. 条件覆盖:条件覆盖的含义是,不仅每个语句至少执行一次,而且使判定表达式中的每个条件都取到各种可能的结果

  4. 判定/条件覆盖:既然判定覆盖不一定包含条件覆盖,条件覆盖也不一定包含判定覆盖,自然会提出一种能同时满足这两种覆盖标准的逻辑覆盖,这就是判定/条件覆盖。

  5. 条件组合覆盖:条件组合覆盖是更强的逻辑覆盖标准,它要求选取足够多的测试数据,使得每个判定表达式中条件的各种可能组合都至少出现一次

  6. 点覆盖

  7. 边覆盖

  8. 路径覆盖:路径覆盖的含义是,选取足够多测试数据,使程序的每条可能路径都至少执行一次

7.6.2 控制结构测试

  1. 基本路径测试

    1. 根据过程设计结果画出相应的流图

    2. 计算流图的环形复杂度

    3. 确定线性独立路径的基本集合

    4. 设计可强制执行基本集合中每条路径的测试用例

  2. 条件测试

    1. 布尔算符错(布尔算符不正确,遗漏布尔算符或有多余的布尔算符)

    2. 布尔变量错

    3. 布尔括弧错

    4. 关系算符错

    5. 算术表达式错

  3. 循环测试

    1. 简单循环

      1. 跳过循环

      2. 只通过循环一次

      3. 通过循环两次

      4. 通过循环m次,其中m<n-1

      5. 通过循环n-1,n,n+1次

    2. 嵌套循环

      1. 从最内层循环开始测试,把所有其他循环都设置为最小值

      2. 对最内层循环使用简单循环测试方法,而使外层循环的迭代参数(例如,循环计数器)取最小值,并为越界值或非法值增加一些额外的测试

      3. 由内向外,对下一个循环进行测试,但保持所有其他外层循环为最小值,其他嵌套循环为“典型”值。

      4. 继续进行下去,直到测试完所有循环

    3. 串接循环

7.7 黑盒测试技术

7.7.1 等价划分

  1. 划分等价类的规则

    1. 如果规定了输入值的范围,则可划分出一个有效的等价类(输入值在此范围内),两个无效的等价类(输入值小于最小值或大于最大值)。

    2. 如果规定了输入数据的个数,则类似地也可以划分出一个有效的等价类和两个无效的等价类。

    3. 如果规定了输入数据的一组值,而且程序对不同输入值做不同处理,则每个允许的输入值是一个有效的等价类,此外还有一个无效的等价类(任一个不允许的输入值)。

    4. 如果规定了输人数据必须遵循的规则,则可以划分出一个有效的等价类(符合规则)和若干个无效的等价类(从各种不同角度违反规则)。

    5. 如果规定了输人数据为整型,则可以划分出正整数、零和负整数3个有效类。

    6. 如果程序的处理对象是表格,则应该使用空表,以及含一项或多项的表。

  2. 测试步骤

    1. 设计一个新的测试方案以尽可能多地覆盖尚未被覆盖的有效等价类,重复这一步骤直到所有有效等价类都被覆盖为止。

    2. 设计一个新的测试方案,使它覆盖一个而且只覆盖一个尚未被覆盖的无效等价类,重复这一步骤直到所有无效等价类都被覆盖为止。

7.7.2 边界值分析

  1. 使输出刚好等于最小的负整数

  2. 使输出刚好等于最大的正整数

  3. 使输出刚刚小于最小的负整数

  4. 使输出刚刚大于最大的正整数

7.7.3 错误推测

7.8 调试

7.8.1 调试过程

在这里插入图片描述
图7-8-1-1 调试过程

7.8.2 调试途径

  1. 蛮干法:按照“让计算机自己寻找错误”的策略,这种方法印出内存的内容,激活对运行过程的跟踪,并在程序中到处都写上WRITE(输出)语句,希望在这样生成的信息海洋的某个地方发现错误原因的线索。

  2. 回溯法:从发现症状的地方开始,人工沿程序的控制流往回追踪分析源程序代码,直到找出错误原因为止。

  3. 原因排除法

    1. 对分查找:如果已经知道每个变量在程序内若干个关键点的正确值,则可以用赋值语句或输人语句在程序中点附近“注入”这些变量的正确值,然后运行程序并检查所得到的输出。

    2. 归纳法:从个别现象推断出一般性结论的思维方法。首先把和错误有关的数据组织起来进行分析,以便发现可能的错误原因。

    3. 演绎法:从一般原理或前提出发,经过排除和精化的过程推导出结论。首先设想出所有可能的出错原因,然后试图用测试来排除每一个假设的原因。

7.9 软件可靠性

7.9.1 基本概念

  1. 软件可靠性的定义:软件可靠性是程序在给定的时间间隔内,按照规格说明书的规定成功地运行的概率

  2. 软件的可用性:软件可用性是程序在给定的时间点,按照规格说明书的规定,成功地运行的概率

7.9.2 估算平均无故障时间的方法

  1. 符号

    1. ET——测试之前程序中错误总数

    2. IT——程序长度(机器指令总数)

    3. τ——测试(包括调试)时间

    4. Ed(τ)——在0至τ期间发现的错误数

    5. Ec(τ)——在0至τ期间改正的错误数

  2. 基本假定

    1. 在类似的程序中,单位长度里的错误数ET/IT近似为常数

    2. 失效率正比于软件中剩余的(潜藏的)错误数,而平均无故障时间MTTF与剩余的错误数成反比

  3. 估算平均无故障时间

  4. 估算错误总数的方法

    1. 植入错误法

    2. 分别测试法

第八章 维护

8.1 软件维护的定义

所谓软件维护就是在软件已经交付使用之后,为了改正错误或满足新的需要而修改软件的过程。

8.2 软件维护的特点

8.2.1 结构化维护与非结构化维护差别巨大

  1. 非结构化维护

  2. 结构化维护

8.2.2 维护的代价高昂

  1. 当看来合理的有关改错或修改的要求不能及时满足时将引起用户不满

  2. 由于维护时的改动,在软件中引入了潜伏的错误,从而降低了软件的质量

  3. 当必须把软件工程师调去从事维护工作时,将在开发过程中造成混乱

8.2.3 维护的问题很多

  1. 理解别人写的程序通常非常困难,而且困难程度随着软件配置成分的减少而迅速增加

  2. 需要维护的软件往往没有合格的文档,或者文档资料显著不足

  3. 当要求对软件进行维护时,不能指望由开发人员给人们仔细说明软件

  4. 绝大多数软件在设计时没有考虑将来的修改

  5. 软件维护不是一项吸引人的工作

8.3 软件维护过程

  1. 维护组织

  2. 维护报告

    1. 满足维护要求表中提出的要求所需要的工作量

    2. 维护要求的性质

    3. 这项要求的优先次序

    4. 与修改有关的事后数据

  3. 维护的事件流
    在这里插入图片描述
    图8-3-1-1 维护阶段的事件流

  4. 保护维护记录

  5. 评价维护活动

    1. 每次程序运行平均失效的次数

    2. 用于每一类维护活动的总人时数

    3. 平均每个程序、每种语言、每种维护类型所做的程序变动数

    4. 维护过程中增加或删除一个源语句平均花费的人时数

    5. 维护每种语言平均花费的人时数

    6. 一张维护要求表的平均周转时间

    7. 不同维护类型所占的百分比

8.4 软件的可维护性

8.4.1 决定软件可维护性的因素

  1. 可理解性:软件可理解性表现为外来读者理解软件的结构、功能、接口和内部处理过程的难易程度

  2. 可测试性:诊断和测试的容易程度取决于软件容易理解的程度

  3. 可修改性

  4. 可移植性:软件可移植性指的是,把程序从一种计算环境(硬件配置和操作系统)转移到另一种计算环境的难易程度

  5. 可重用性:同一事物不做修改或稍加改动就在不同环境中多次重复使用

8.4.2文档

  1. 文档要求

    1. 必须描述如何使用这个系统,没有这种描述时即使是最简单的系统也无法使用

    2. 必须描述怎样安装和管理这个系统

    3. 必须描述系统需求和设计

    4. 必须描述系统的实现和测试,以便使系统成为可维护的

  2. 用户文档

    1. 功能描述,说明系统能做什么

    2. 安装文档,说明怎样安装这个系统以及怎样使系统适应特定的硬件配置

    3. 使用手册,简要说明如何着手使用这个系统(应该通过丰富例子说明怎样使用常用的系统功能,还应该说明用户操作错误时怎样恢复和重新启动)

    4. 参考手册,详尽描述用户可以使用的所有系统设施以及它们的使用方法,还应该解释系统可能产生的各种出错信息的含义(对参考手册最主要的要求是完整,因此通常使,用形式化的描述技术)

    5. 操作员指南(如果需要有系统操作员的话),说明操作员应该如何处理使用中出现的各种情况

  3. 系统文档:从问题定义、需求说明到验收测试计划这样一系列和系统实现有关的文档

8.4.3 可维护性复审

8.5 预防性维护

  1. 为了修改这类程序以适应用户新的或变更的需求,有以下几种做法可供选择

    1. 反复多次地做修改程序的尝试,与不可见的设计及源代码“顽强战斗”,以实现所要求的修改

    2. 通过仔细分析程序尽可能多地掌握程序的内部工作细节,以便更有效地修改它

    3. 在深人理解原有设计的基础上,用软件工程方法重新设计、重新编码和测试那些需要变更的软件部分

    4. 以软件工程方法学为指导,对程序全部重新设计、重新编码和测试,为此可以使用CASE工具(逆向工程和再工程工具)来帮助理解原有的设计

  2. 维护的问题

    1. 维护一行源代码的代价可能是最初开发该行源代码代价的14~40倍

    2. 重新设计软件体系结构(程序及数据结构)时使用了现代设计概念,它对将来的维护可能有很大的帮助

    3. 由于现有的程序版本可作为软件原型使用,开发生产率可大大高于平均水平

    4. 用户具有较多使用该软件的经验,因此,能够很容易地搞清新的变更需求和变更的范围

    5. 利用逆向工程和再工程的工具,可以使一部分工作自动化

    6. 在完成预防性维护的过程中可以建立起完整的软件配置

8.6 软件再生过程

在这里插入图片描述
图8-6-1-1 软件再工程过程模型

  1. 库存目录分析

  2. 文档重构

  3. 逆向工程

  4. 代码重构

  5. 数据重构

  6. 正向工程

第九章 面向对象方法学引论

9.1 面向对象方法学概述

9.1.1 面向对象方法学的要点

  1. 认为客观世界是由各种对象组成的,任何事物都是对象,复杂的对象可以由比较简单的对象以某种方式组合而成

  2. 把所有对象都划分成各种对象类(简称为类,class),每个对象类都定义了一组数据和一组方法

  3. 按照子类(或称为派生类)与父类(或称为基类)的关系,把若干个对象类组成一个层次结构的系统(也称为类等级)

  4. 对象彼此之间仅能通过传递消息互相联系

9.1.2 面向对象方法学的优点

  1. 与人类习惯的思维方法一致

  2. 稳定性好

  3. 可重用性好

  4. 较易开发大型软件产品

  5. 可维护性好

    1. 面向对象的软件稳定性比较好

    2. 面向对象的软件比较容易修改

    3. 面向对象的软件比较容易理解

    4. 易于测试和调试

9.2 面向对象的概念

9.2.1 对象

  1. 对象的形象表示

  2. 对象的定义

    1. 对象是具有相同状态的一组操作的集合。

    2. 对象是对问题域中某个东西的抽象,这种抽象反映了系统保存有关这个东西的信息或与它交互的能力。

    3. 对象::=<ID,MS,DS,MI>。

  3. 对象的特点

    1. 以数据为中心

    2. 对象是主动的

    3. 实现了数据封装

    4. 本质上具有并行性

    5. 模块独立性好

9.2.2 其他概念

  1. 类:把有相似特征的事物归为一类

  2. 实例:实例就是由某个特定的类所描述的一个具体的对象

  3. 消息

    1. 接收消息的对象

    2. 消息选择符(也称为消息名)

    3. 零个或多个变元

  4. 方法:对象所能执行的操作,也就是类中所定义的服务

  5. 属性:类中所定义的数据,它是对客观世界实体所具有的性质的抽象

  6. 封装:把某个事物包起来,使外界不知道该事物的具体内容

    1. 有一个清晰的边界。所有私有数据和实现操作的代码都被封装在这个边界内,从外面看不见更不能直接访问。

    2. 有确定的接口(即协议)。这些接口就是对象可以接受的消息,只能通过向对象发送消息来使用它。

    3. 受保护的内部实现。实现对象功能的细节(私有数据和代码)不能在定义该对象的类的范围外访问。

  7. 继承:能够直接获得已有的性质和特征,而不必重复定义它们

  8. 多态性:子类对象可以像父类对象那样使用,同样的消息既可以发送给父类对象也可以发送给子类对象。

  9. 重载

    1. 函数重载是指在同一作用域内的若干个参数特征不同的函数可以使用相同的函数名字

    2. 运算符重载是指同一个运算符可以施加于不同类型的操作数上面

9.3 面向对象建模

9.4对象模型

9.4.1 类图的基本符号

  1. 定义类

    1. 使用标准术语。

    2. 使用具有确切含义的名词。

    3. 必要时用名词短语作名字。

  2. 定义属性

  3. 定义服务

9.4.2 表示关系的符号

  1. 关联

    1. 普通关联
      在这里插入图片描述
      图9-4-2-1 普通关联示例

    2. 关联的角色
      在这里插入图片描述
      图9-4-2-2 关联的角色

    3. 限定关联
      在这里插入图片描述
      图9-4-2-3 一个受限的关联

    4. 关联类
      在这里插入图片描述
      图9-4-2-4 关联类示例

  2. 聚集

    1. 共享聚集
      在这里插入图片描述
      图9-4-2-5 共享聚集示例

    2. 组合聚集
      在这里插入图片描述
      图9-4-2-6 组合聚集示例

  3. 泛化

    1. 普通泛化

    2. 受限泛化

  4. 依赖和细化

    1. 依赖关系
      在这里插入图片描述
      图9-4-2-7 友元依赖关系

    2. 细化关系
      在这里插入图片描述
      图9-4-2-8 细化关系示例

9.5 动态模型

动态模型表示瞬时的、行为化的系统的“控制”性质,它规定了对象模型中的对象的合法变化序列。
所有对象都具有自己的生命周期(或称为运行周期)

9.6 功能模型

9.6.1 用例图

在这里插入图片描述
图9-6-1-1 自动售货机系统用例图

  1. 系统:代表系统的方框的边线表示系统的边界,用于划定系统的功能范围,定义了系统所具有的功能。描述该系统功能的用例置于方框内,代表外部实体的行为者置于方框外。

  2. 用例:一个用例是可以被行为者感受到的、系统的一个完整的功能

    1. 用例代表某些用户可见的功能,实现一个具体的用户目标。

    2. 用例总是被行为者启动的,并向行为者提供可识别的值。

    3. 用例必须是完整的。

  3. 行为者:行为者是指与系统交互的人或其他系统,它代表外部实体。使用用例并且与系统交互的任何人或物都是行为者。

  4. 用例之间的关系

    1. 扩展关系:向一个用例中添加一些动作后构成了另一个用例,这两个用例之间的关系就是扩展关系,后者继承前者的一些行为,通常把后者称为扩展用例。

    2. 使用关系:当一个用例使用另一个用例时,这两个用例之间就构成了使用关系。
      在这里插入图片描述
      图9-6-1-2 含扩展和使用关系的用例图

9.6.2 用例建模

  1. 寻找行为者

  2. 寻找用例

9.7 3种模型之间的关系

  1. 针对每个类建立的动态模型,描述了类实例的生命周期或运行周期

  2. 状态转换驱使行为发生,这些行为在数据流图中被映射成处理,在用例图中被映射成用例,它们同时与类图中的服务相对应

  3. 功能模型中的处理(或用例)对应于对象模型中的类所提供的服务

  4. 数据流图中的数据存储,以及数据的源点/终点,通常是对象模型中的对象

  5. 数据流图中的数据流,往往是对象模型中对象的属性值,也可能是整个对象

  6. 用例图中的行为者,可能是对象模型中的对象

  7. 功能模型中的处理(或用例)可能产生动态模型中的事件

  8. 对象模型描述了数据流图中的数据流、数据存储以及数据源点/终点的结构

第十章 面向对象分析

10.1 面向对象分析的基本过程

10.1.1 概述

面向对象分析,就是抽取和整理用户需求并建立问题域精确模型的过程。

  1. 面向对象分析过程从分析陈述用户需求的文件开始
  2. 接下来,系统分析员应该深入理解用户需求,抽象出目标系统的本质属性,并用模型准确地表示出来
  3. 在面向对象建模的过程中,系统分析员必须认真向领域专家学习
  4. 在面向对象建模的过程中,还应该仔细研究以前针对相同的或类似的问题域进行面向对象分析所得到的结果(可重用)

10.1.2 3个子模型与5个层次

  1. 主题层

  2. 类与对象层

  3. 结构层

  4. 属性层

  5. 服务层

10.2 需求陈述

10.2.1 书写要点

书写需求陈述时,要尽力做到语法正确,而且应该慎重选用名词、动词、形容词和同义词。

10.2.2 例子

在这里插入图片描述
图10-2-2-1 ATM系统

10.3 建立对象模型

10.3.1 确定类与对象

  1. 找出候选的类与对象

    1. 可感知的物理实体,例如,飞机、汽车、书、房屋等。

    2. 人或组织的角色,例如,医生、教师、雇主、雇员、计算机系、财务处等。

    3. 应该记忆的事件,例如,飞行、演出、访问、交通事故等。

    4. 两个或多个对象的相互作用,通常具有交易或接触的性质,例如,购买、纳税、结婚等。

    5. 需要说明的概念,例如,政策、保险政策、版权法等。

  2. 筛选出正确的类与对象

    1. 荣誉

    2. 无关

    3. 笼统

    4. 属性

    5. 操作

    6. 实现

10.3.2 确定关联

  1. 初步确定关联

    1. 直接提取动词短语得出的关联

    2. 需求陈述中隐含的关联

    3. 根据问题域知识得出的关联

  2. 筛选

    1. 已删去的类之间的关联

    2. 与问题无关的或应在实现阶段考虑的关联

    3. 瞬时事件

    4. 三元关联

    5. 派生关联

  3. 进一步完善

    1. 正名

    2. 分解

    3. 补充

    4. 标明重数
      在这里插入图片描述
      图10-3-2-1 ATM系统原始的类图

10.3.3 划分主题

  1. 在开发很小的系统时,可能根本无须引入主题层
  2. 对于含有较多对象的系统,则往往先识别出类与对象和关联,然后划分主题,并用它作为指导开发者和用户观察整个模型的一种机制
  3. 对于规模极大的系统,则首先由高级分析员粗略地识别对象和关联,然后初步划分主题,经进一步分析,对系统结构有更深入的了解之后,再进一步修改和精炼主题

10.3.4 确定属性

  1. 分析

  2. 选择

    1. 误把对象当作属性

    2. 误把关联类的属性当作一般对象的属性

    3. 把限定误当成属性

    4. 误把内部状态当成了属性

    5. 过于细化

    6. 存在不一致的属性
      在这里插入图片描述
      图10-3-4-1 ATM系统对象模型中的属性

10.3.5 识别继承关系

  1. 自底向上:抽象出现有类的共同性质泛化出父类,这个过程实质上模拟了人类归纳思维过程。

  2. 自顶向下:把现有类细化成更具体的子类,这模拟了人类的演绎思维过程。

在这里插入图片描述
图10-3-5-1 带有继承关系的ATM对象模型.

10.3.6 反复修改

  1. 分解“现金兑换卡”类

  2. “事务”由“更新”组成

  3. 把“分行”与“分行计算机”合并
    在这里插入图片描述
    10-3-6-1 修改后的ATM对象模型

10.4 建立动态模型

10.4.1 编写脚本

  1. 首先编写正常情况的脚本
  2. 然后,考虑特殊情况,例如输入或输出的数据为最大值(或最小值)
  3. 最后,考虑出错情况,例如,输入的值为非法值或响应失败。对大多数交互式系统来说,出错处理都是最难实现的部分。如果可能,应该允许用户“异常中止”一个操作或“取消”一个操作
  4. 此外,还应该提供诸如“帮助”和状态查询之类的在基本交互行为之上的“通用”交互行为

10.4.2 设想用户界面

大多数交互行为都可以分为应用逻辑和用户界面两部分。通常,系统分析员首先集中精力考虑系统的信息流和控制流,而不是首先考虑用户界面。
事实上,采用不同界面(例如命令行或图形用户界面),可以实现同样的程序逻辑。应用逻辑是内在的、本质的内容,用户界面是外在的表现形式。动态模型着重表示应用系统的控制逻辑。
但是,用户界面的美观程度、方便程度、易学程度以及效率等,是用户使用系统时最先感受到的,用户对系统的“第一印象”往往从界面得来,用户界面的好坏往往对用户是否喜欢、是否接受一个系统起很重要的作用

10.4.3 画事件跟踪图

  1. 确定事件

  2. 画出事件跟踪图
    在这里插入图片描述
    图10-4-3-1 ATM系统正常情况脚本的事件跟踪图

10.4.4 画状态图

在这里插入图片描述
图10-4-4-1 ATM类的状态图

在这里插入图片描述
图10-4-4-2 总行类的状态图
在这里插入图片描述
图10-4-4-3 分行类的状态图

10.4.5审查动态模型

对于没有前驱或没有后继的状态应该着重审查

10.5建立功能模型

10.5.1画出基本系统模型图

在这里插入图片描述
图10-5-1-1 ATM系统的基本系统模型

10.5.2画出功能级数据流图

在这里插入图片描述
图10-5-2-1 ATM系统的功能级数据流图

10.5.3描述处理框功能

把数据流图分解细化到一定程度之后,就应该描述图中各个处理框的功能。应该注意的是,要着重描述每个处理框所代表的功能,而不是实现功能的具体算法。
描述既可以是说明性的,也可以是过程性的。

  1. 说明性描述规定了输入值和输出值之间的关系,以及输出值应遵循的规律。
  2. 过程性描述则通过算法说明“做什么”

一般说来,说明性描述优于过程性描述,因为这类描述中通常不会隐含具体实现方面的考虑。

10.6 定义服务

  1. 常规行为

  2. 从事件导出的操作

  3. 与数据流图中处理框对应的操作

  4. 利用集成减少冗余操作

第十一章 面向对象设计

11.1 面向对象分析的准则

  1. 模块化:面向对象软件开发模式,很自然地支持了把系统分解成模块的设计原理:对象就是模块。

  2. 抽象:面向对象方法不仅支持过程抽象,而且支持数据抽象。

  3. 信息隐藏:在面向对象方法中,信息隐藏通过对象的封装性实现:类结构分离了接口与实现,从而支持了信息隐藏。

  4. 弱耦合:耦合是指一个软件结构内不同模块之间互连的紧密程度

    1. 交互耦合:如果对象之间的耦合通过消息连接来实现,则这种耦合就是交互耦合

    2. 集成耦合:与交互耦合相反,应该提高继承耦合程度

  5. 强内聚

    1. 服务内聚。一个服务应该完成一个且仅完成一个功能。

    2. 类内聚。设计类的原则是,一个类应该只有一个用途,它的属性和服务应该是高内聚的。

    3. )一般-特殊内聚。设计出的一般-特殊结构,应该符合多数人的概念,更准确地说,这种结构应该是对相应的领域知识的正确抽取。

  6. 可重用:软件重用是提高软件开发生产率和目标系统质量的重要途径

11.2 启发规则

  1. 设计结果应该清晰易懂

    1. 用词一致

    2. 使用已有的协议

    3. 减少消息模式的数目

    4. 避免模糊的定义

  2. 一般-特殊结构的深度应适当:应该使类等级中包含的层次数适当

  3. 设计简单的类:应该尽量设计小而简单的类,以便于开发和管理

    1. 避免包含过多的属性

    2. 有明确的定义

    3. 尽量简化对象之间的合作关系

    4. 不要提供太多服务

  4. 使用简单的协议

  5. 使用简单的服务

  6. 把设计变动减至最小

11.3 软件重用

11.3.1 概述

  1. 重用

    1. 知识重用(例如软件工程知识的重用)。

    2. 方法和标准的重用(例如,面向对象方法或国家制定的软件开发规范的重用)。

    3. 软件成分的重用。

  2. 软件成分的重用级别

    1. 代码重用

    2. 设计结果重用

    3. 分析结果重用

  3. 典型的可重用软件成分

    1. 项目计划

    2. 成本估计

    3. 体系结构

    4. 需求模型和规格说明

    5. 设计

    6. 源代码

    7. 用户文档和技术文档

    8. 用户界面

    9. 数据

    10. 测试用例

11.3.2 类构件

  1. 可重用软构件应具备的特点

    1. 模块独立性强。

    2. 具有高度可塑性。

    3. 接口清晰、简明、可靠。

  2. 类构件的重用方式

    1. 实例重用

    2. 继承重用

    3. 多态重用

11.3.3 软件重用的效益

  1. 质量

  2. 生产率

  3. 成本

11.4 系统分解

  1. 子系统之间的两种交互方式

    1. 客户-供应商关系

    2. 平等伙伴关系

  2. 组织系统的两种方案

    1. 组织层次

    2. 块状组织

  3. 设计系统的拓扑结构

11.5 设计问题域子系统

  1. 调整需求

  2. 重用已有的类

  3. 把问题域类组合在一起

  4. 增添一般化类以建立协议

  5. 调整继承层次

  6. ATM系统实例

11.6 设计人机交互子系统

  1. 分类用户

  2. 描述用户

  3. 设计命令层次

  4. 设计人机交互类

11.7 设计任务管理子系统

  1. 分析并发性

  2. 设计任务管理子系统

11.8 设计数据管理子系统

11.8.1 选择数据存储管理模式

  1. 文件管理系统

  2. 关系数据库管理系统

  3. 面向对象数据库管理系统

11.8.2 设计数据管理子系统

  1. 设计数据格式

    1. 文件系统

    2. 关系数据库管理系统

    3. 面向对象数据库管理系统

  2. 设计相应的服务

    1. 文件系统

    2. 关系数据库管理系统

    3. 面向对象数据库管理系统

11.8.3 例子

11.9 设计类中的服务

11.9.1 确定类中应有的服务

确定类中应有的服务需要综合考虑对象模型、动态模型和功能模型,才能正确确定类中应有的服务。对象模型是进行对象设计的基本框架。

11.9.2 设计实现服务的方法

  1. 设计实现服务的算法

  2. 选择数据结构

  3. 算法与数据结构的关系

  4. 定义内部类和内部操作

11.10 设计关联

  1. 关联的遍历

  2. 实现单向关联

  3. 实现双向关联

  4. 关联对象的实现

11.11 设计优化

11.11.1 确定优先级

系统的各项质量指标并不是同等重要的,设计人员必须确定各项质量指标的相对重要性(即确定优先级),以便在优化设计时制定折衷方案。

11.11.2 提高效率的几项技术

  1. 增加冗余关联以提高访问效率

  2. 调整查询次序

  3. 保留派生属性

11.11.3 调整继承关系

  1. 抽象与具体

  2. 为提高继承程度而修改类定义

  3. 利用委托实现行为共享

第十二章 面向对象实现

12.1 程序设计语言

12.1.1 面向对象语言的优点

  1. 一致的表示方法

  2. 可重用性

  3. 可维护性

12.1.2 面向对象语言的技术特点

  1. 支持类与对象概念的机制

  2. 实现整体-部分(即聚集)结构的机制

  3. 实现一般-特殊(即泛化)结构的机制

  4. 实现属性和服务的机制

  5. 类型检查

  6. 类库

  7. 效率

  8. 持久保存对象

  9. 参数化类

  10. 并发环境

12.1.3 选择面向对象语言

  1. 将来能否占主导地位

  2. 可重用性

  3. 类库和开发环境

  4. 其他因素

12.2 程序设计风格

12.2.1 提高可重用性

  1. 提高方法的内聚

  2. 减小方法的规模

  3. 保持方法的一致性

  4. 把策略与实现分开

  5. 全面覆盖

  6. 尽量不使用全局信息

  7. 利用继承机制

12.2.2 提高可扩充性

  1. 封装实现策略

  2. 不要用一个方法遍历多条关联链

  3. 避免使用多分支语句

  4. 精心确定公有方法

12.2.3 提高健壮

  1. 预防用户的操作错误

  2. 检查参数的合法性

  3. 不要预先确定限制条件

  4. 先测试后优化

12.3 测试策略

12.3.1 面向对象的单元测试

最小的可测试单元是封装起来的类和对象。一个类可以包含一组不同的操作,而一个特定的操作也可能存在于一组不同的类中。因此,对于面向对象的软件来说,单元测试的含义发生了很大变化。

12.3.2 面向对象的集成测试

  1. 基于线程的测试

  2. 基于使用的测试

12.3.3 面向对象的确认测试

在确认测试或系统测试层次,不再考虑类之间相互连接的细节。和传统的确认测试一样,面向对象软件的确认测试也集中检查用户可见的动作和用户可识别的输出。为了导出确认测试用例,测试人员应该认真研究动态模型和描述系统行为的脚本,以确定最可能发现用户交互需求错误的情景。

12.4 设计测试用例

12.4.1 测试类的方法

  1. 随机测试
  2. 划分测试
    1. 基于状态的划分
    2. 基于属性的划分
    3. 基于功能的划分
  3. 基于故障的测试

12.4.2 集成测试方法

  1. 多类测试

  2. 从动态模型导出测试用例

第十三章 软件项目管理

13.1 估计软件规模

13.1.1 代码行技术

13.1.2 功能点技术

  1. 信息域特点

  2. 估算功能点的步骤

13.2 工作量估算

13.2.1 静态单变量模型

  1. 面向KLOC的估算模型

  2. 面向FP的估算模型

13.2.2 动态多变量模型

13.2.3 COCOMO2模型

13.3 进度计划

13.3.1 估算开发时间

13.3.2 Gantt图

13.3.3 工程网络

13.3.4 估算工程进度

13.3.5 关键路径

13.3.6 机动时间

13.4 人员组织

13.4.1 民主制程序员组

13.4.2 主程序员组

13. 4.3 现代程序员

13.5 质量保证

13.5.1 软件质量

13.5.2 软件质量保证措施

  1. 技术复审的必要性

  2. 走查

  3. 审查

  4. 程序正确性证明

13.6 软件配置管理

13.6.1 软件配置

  1. 软件配置项

  2. 基线

13.6.2 软件配置管理过程

  1. 标识软件配置中的对象

  2. 版本控制

  3. 变化控制

  4. 配置审计

  5. 状态报告

13.7能力成熟度模型

  1. 初始级

  2. 可重复级

  3. 已定义级

  4. 已管理级

  5. 优化级

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码两年半的练习生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值