# 软件工程


## 一、软件过程

### 软件过程的概念

软件过程是指工作产品构建时所执行的一系列活动、动作和任务的集合．

软件过程是指软件整个生命周期，从需求获取、需求分析、设计、实现、测试、发布和维护一个过程模型．

### 经典软件过程模型的特点

#### 瀑布模型

瀑布模型提供了一个统一的、顺序的软件开发方法，从用户需求规格说明开始，通过策划、建模、构建和部署的过程，最终提供完整的软件支持．

特征
- 接受上一阶段的结果作为本阶段的输入
- 利用这一输入实施本阶段应完成的活动
- 对本阶段的工作进行评审
- 将本阶段的结果作为输出，传递给下一阶段

缺点
- 实际的项目很少遵守瀑布模型提出的顺序
- 缺乏灵活性，难以适应需求???确或需求经常变化的软件开发
- 开发早期存在的问题往往要到交付使用时才发现，维护代价大

#### 增量模型

增量模型将软件的开发过程分成若干个日程时间交错的线性序列，每个线性序列产生软件的一个可发布的“增量”版本，后一版本是对前一版本的修改和补充，重复增量发布的过程，直至产生最终的完善产品．

#### 演化模型

软件往往难以一次开发完成，我们可以在获取了一组基本的需求后，通过快速分析，构造出该软件的一个初始版本，称为原型（prototype），然后根据用户在试用原型的过程中提出的反馈意见和建议对原型进行改进，获得原型的新版本，重复这一过程，最终可得到令用户满意的软件产品．

#### 统一过程模型

### 过程评估与CMM/CMMI的基本概念

CMM（Capability Maturity Model）即能力成熟度模型，用于评价软件机构的软件过程能力成熟度的模型．

### 敏捷宣言与敏捷过程的特点

**敏捷宣言**
- 个体和交互胜过过程和工具
- 可工作软件胜过宽泛的文档
- 客户合作胜过合同谈判
- 响应变化胜过遵循计划
- 右边的各项很有价值，但左边的价值更大

**敏捷过程**
- 敏捷开发的过程有着更强的适应性而不是预设性
- 敏捷开发的过程中，更加的注重人的因素
- 在敏捷开发的过程中，整个项目是测试驱动的而不是文档驱动的

----

## 二、软件需求

### 软件需求的概念

需求分析是研究用户要求，以得到目标系统的需求定义的过程．

需求分析的基本任务是软件开发人员和用户一起完全弄清用户对系统的确切要求．

### 需求工程的基本过程

软件需求工程细分为：需求获取、需求分析与协商、系统建模、需求规约、需求验证和需求管理六个阶段．

### 分层数据流模型

### 用例和场景建模及其UML表达

#### 用例图

**用例图**展示了各类外部执行者与系统所提供的用例之间的连接。

用例图由**参与者**（Actor）、**用例**（Use Case）、**系统边界**、**关系**组成．其中关系包括关联、扩展、包含、泛化等．

创建用例模型的步骤包括：

1. 定义系统
2. 确定参与者
3. 确定用例
4. 描述用例
5. 定义用例间的关系
6. 确认模型

用例图中的矩形框代表系统，系统的用例画在矩形框内，代表系统之外的参与者画在矩形框外．

![usecase.png](usecase.png)

#### 活动图

![activity.png](activity.png)

#### 泳道图

#### 顺序图

顺序图主要用来显示对象之间发送消息的顺序，以及对象之间的交互．

![sequence.png](sequence.png)

### 数据模型建模及其UML表达

#### 类图

类图展示系统中类的静态结构，即类与类之间的相互联系．

### 行为模型建模及其UML表达

#### 状态图

状态图通常是对类描述的补充，它说明该类的对象所有可能的状态以及哪些事件将导致状态的变化．

![state.png](state.png)

----

## 三、软件设计与构造

### 软件体系结构及体系结构风格的概念

程序或计算机系统的软件体系结构是指系统的一个或者多个结构，它包括软件构件、构件的外部可见属性以及它们之间的相互关系．

体系结构风格就是施加在整个系统上的一种变换，目的是为系统的所有构件建立一个结构．

体系结构风格的简单分类
- 以数据为中心的体系结构
- 数据流体系结构
- 调用和返回体系结构
- 面向对象体系结构
- 层次体系结构

### 设计模式的概念

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结．使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性．

### 模块化设计的基本思想及概念

#### 抽象

抽象是一种思考和解决问题的形式，它集中注意事物某个一般性级别上的问题，避开不必要的底层细节．抽象可以分成若干级别，级别越高，细节就越少．

抽象是忽略一个问题中与当前目标无关的那些方面，以便更充分地关注与当前目标有关的方面．

#### 分解

分解是将问题不断分解为较小的问题，直到每个最底层的问题都足够简单为止．

#### 模块化

模块化是把软件按照规定原则，划分为一个个较小的，相互独立的但又相互关联的部件，实际上是系统分解和抽象的过程．

合理的软件结构应该是分块的结构，即软件应该分解成可单独命名的且可访问的部件，这些部件称为模块．这种将软件分成具有一定结构的模块的过程成为模块化．

#### 封装

封装是一种信息隐蔽技术，用户只能看见对象封装界面上的信息，对象的内部实现对用户是隐蔽的。封装的目的是使对象的使用者和生产者分离，使对象的定义和实现分开。

#### 信息隐藏

信息隐藏是指模块中所包含的信息对不需要这些信息的其他模块是不可访问的．这样，每一个将来可能的改变都会局部于一个特定的模块，改变该模块的内部过程或数据的设计不会影响到其他模块．

#### 功能独立

功能独立是模块化、抽象、信息隐藏和局部化等概念的直接结果．开发功能专一的且避免与其他模块过多交互的的模块可以实现功能独立．

### 软件重构的概念

软件重构是指在不改变软件的功能和外部可见性的情况下，为了改善软件的结构，提高软件的清晰性、可扩展性和可重用性而对其进行的改造．

### 软件体系结构的UML建模

#### 包图

包图是由包和包之间的关系组成的结构图，在某一视点给定的精度上对系统的完整描述．

#### 类图

类图展示系统中类的静态结构，即类与类之间的相互联系．

#### 构件图

构件图展示以代码构建为单位的代码的物理结构．

#### 顺序图

顺序图主要用来显示对象之间发送消息的顺序，以及对象之间的交互．

#### 部署图

部署图展示系统中硬件和软件的物理结构．

### 接口的概念

接口提供关于通信和协作的重要信息，然而接口表示的随意性会使构件图趋于复杂化．

### 面向对象设计原则

#### 单一职责原则

类的职责要单一，不能将太多的职责放在一个类中．

#### 开闭原则

软件实体对扩展是开放的，但对修改是关闭的，即在不修改一个软件实体的基础上去扩展其功能．

#### Liskov替换原则

在软件系统中，一个可以接受基类对象的地方必然可以接受一个子类对象．

#### 依赖转置原则

要针对抽象层编程，而不要针对具体类编程．

#### 接口隔离原则

使用多个专门的接口来取代一个统一的接口．

### 内聚与耦合的概念

内聚是模块相对功能性的度量，即一个模块内部各个元素彼此结合的紧密程度的度量．

耦合是模块间相对独立性的度量，即模块间相互连接的紧密程度的度量．

模块独立性比较强的模块应是高内聚低耦合的模块．

### 常见的内聚和耦合类型

内聚类型
- 偶然内聚
- 逻辑内聚
- 时间内聚
- 过程内聚
- 通信内聚
- 顺序内聚
- 功能内聚

耦合类型
- 数据耦合
- 控制耦合
- 特征耦合
- 公共环境耦合
- 内容耦合

----

## 四、软件测试

### 软件测试及测试用例的概念

软件测试是一种能够系统的加以计划和说明的过程，可以进行测试用例设计，定义测试策略，根据预期的结果评估测试结果．其目的是为了发现软件设计和实现过程中因疏忽所造成的错误．

测试用例是为特定的目的而设计的一组测试输入、执行条件和预期的结果，以便测试是否满足某个特定需求．

#### 单元测试

单元测试也称模块测试，一般在编码阶段进行，主要测试模块功能和内部逻辑

测试方法：白盒

发现错误：编码、详细设计

#### 集成测试

集成测试是根据程序结构图将模块集成为程序进行测试，主要测试模块间的接口和通信

测试方法：黑盒

发现错误：概要设计

#### 确认测试

确认测试是根据需求规格说明，检查软件的功能及其它特征是否与用户的需求一致

测试方法：黑盒

发现错误：需求分析

#### 系统测试

系统测试是将软件、硬件、数据库等集成为计算机系统，检查系统的功能、性能等是否符合计算机系统的要求

测试方法：黑盒

发现错误：系统工程

#### 回归测试

回归测试是对某些已经进行过的测试的子集的重新执行，以保证软件的改变不会传播不可预料的副作用或附加的错误．

### 调试的概念

调试不是测试，但总是发生在测试之后．当测试用例发现错误时，调试是使错误消除的过程．

### 调试与测试的关系

测试主要是发现错误，调试则是确定错误的原因和准确位置，并加以纠正．

### 测试覆盖度的概念

### 白盒测试、黑盒测试的概念

白盒测试是把测试对象看作一个透明的盒子，它允许测试人员利用程序内部的逻辑结构及有关信息，设计或选择测试用例，检查程序中的所有逻辑路径是否都按预定的要求正确的工作．

黑盒测试是把测试对象看作一个黑盒子，测试人员完全不考虑程序内部的逻辑结构和内部特性，只依据程序的需求规格说明书，检查程序的功能是否符合它的功能说明．

### 代码圈复杂度的计算方法

圈复杂度是一种软件度量，它为程序的逻辑复杂度提供了一个量化的测度．在基本路径测试方法的环境下，圈复杂度的值定义了程序基本集合中的独立路径数，并提供了保证所有语句至少执行一次所需要测试数量的上限．

圈复杂度以图论为基础，计算方法如下

1. 流图中域的数量与圈复杂度相对应(划分成几个区域)
2. 流图G中，圈复杂度V(G) = E - N + 2，其中E为边数，N为结点数
3. 流图G中，圈复杂度V(G) = P + 1，其中P为判定节点数(IF/CASE语句)

### 白盒测试中的基本路径测试方法

### 黑盒测试中的等价类划分方法

----

<!-- EOF -->


