软件工程笔记

王老师软件工程课笔记

Part I 绪论

1、软件危机的定义

  • 软件规模增长,复杂度增加,导致超预算、完成脱期、质量下降。

  • 可靠性随规模增长而下降。

2、软件危机的成因

  • 维护费用急剧上升,占软件总费用的大部分,包括纠错性维护、适应性维护和完善性维护。

  • 软件技术进步缓慢;软件复杂度增长,而生产方式仍是手工;早期个人自由化开发的软件难以维护。

3、软件工程的范畴

  • 软件开发技术:包括开发方法学、开发工具、软件工程环境。

  • 软件工程管理:包括软件管理学、软件度量学、软件经济学。

4、3种编程范式

  1. 过程式编程范式:程序 = 数据结构 + 算法,自顶向下逐步求精,如
    Pascal,难以维护。

  2. 面向对象编程范式:数据及操作封装于对象中,强调对象与消息。

  3. 基于构件技术的编程范型:通用的可复用组件,支持跨平台运行。

5、三代软件工程的区别

  1. 传统软件工程:结构化分析、结构化设计、面向过程编码与测试。

  2. 面向对象的软件工程:OO
    分析、对象提取、详细设计、面向对象编码与测试。

  3. 基于构件的软件工程:领域分析、构件设计、建立可复用构件库,按构件集成模型开发。

Part II 生命周期与过程

1、软件生命周期

软件从立项开始到废止为止,大致分为计划、开发和运行三个时期。

典型的软件生存周期包括:

1
需求分析 → 软件分析 → 软件设计 → 编码 → 测试 → 运行维护

2、传统软件过程模型

瀑布模型(Waterfall Model)

  • 阶段顺序执行,前一阶段完成后才能进入下一阶段。

  • 各阶段有明确输出,作为下一阶段输入。

  • 推迟实现:逻辑设计与物理实现分离。

  • 质量保证:每个阶段需编写文档并复审。

快速原型模型(Prototyping Model)

  • 先建立一个符合用户初步需求的原型系统。

  • 用户通过原型明确需求,开发者根据反馈改进。

  • 是获取真实需求的一种有效方法。

增量模型(Incremental Model)

  • 瀑布模型与快速原型模型的结合。

  • 软件被划分为多个增量,每个增量独立完成开发。

  • 每次迭代交付一个可运行的子系统。

螺旋模型(Spiral Model)

  • 在瀑布模型和快速原型模型基础上演变而来。

  • 每个周期包含:计划 → 风险分析 → 建立原型 → 用户评审。

  • 适用于大型复杂软件项目。

构件集成模型(Component Integration Model)

  • 将数据和操作封装为对象,称为"类"。

  • 设计和实现的类可作为构件,具有通用性和复用性。

  • 构件存入构件库,供后续开发使用。

3、构件集成模型的特点

  1. 使用预先封装好的构件来构造应用软件系统。

  2. 融合了螺旋模型的特性,支持迭代开发。

  3. 软件开发与构件开发可并行进行,主要用于面向对象开发。

4、统一过程(RUP)

统一过程(Rational Unified Process)是一种迭代式软件开发过程。

四个阶段:

  • 初始阶段:判定项目是否可行。

  • 细化阶段:用例细化、风险分析、生成系统框架。

  • 构造阶段:识别剩余用例,进行迭代开发与质量检测。

  • 迁移阶段:验收产品,制作用户文档,部署上线。

每个阶段分为若干次迭代,每次迭代包含多个工作流:

1
需求 → 分析 → 设计 → 实现 → 测试 → 维护

5、软件可行性研究

  • 目的:判断待开发项目是否值得进行。

  • 内容:包括经济可行性、技术可行性、运行可行性和法律可行性。

Part III 结构化分析与设计

1、结构化分析与设计的任务

  • 建立系统的分析模型。

  • 编写《软件需求规格说明书》。

2、结构化分析的指导思想

  • 抽象:忽略与目标无关的细节,提取关键特征。

  • 分解:将复杂系统分解为若干子系统,逐步细化。

3、SA模型的构成

结构化分析(SA)模型以 数据字典 为核心,主要包括:

  • 实体联系图(ER图):描述数据对象及其关系。

  • 数据流图(DFD):描述系统中数据的流动和处理过程。

  • 状态转换图(STD):描述系统状态的变化及控制逻辑。

数据流图(DFD)基本符号

  • 圆框:表示加工(处理)。

  • 方框:表示数据源点或终点。

  • 箭头:表示数据流向。

  • 双杠:表示数据文件或数据库。

4、SD模型的结构

结构化设计(SD)模型包括以下四个方面:

  • 体系结构设计:定义系统的整体结构。

  • 接口设计:定义模块之间的接口。

  • 过程设计:定义每个模块的算法逻辑。

  • 数据设计:定义数据结构。

5、从DFD图到SC图的过程

  • 变换型结构:由传入路径、变换中心和传出路径组成。

  • 事务型结构:包含一条接受路径、一个事务中心和若干条动作路径。

6、优化SC图的原则

  1. 合理划分模块,保持模块独立性。

  2. 遵循"高扇入,低扇出"的原则。

7、模块设计与结构化设计的关系

  • 模块设计是结构化设计的细化。

  • 目的是为SC图中的每个模块确定算法和内部数据结构。

  • 使用合适的表达工具(如流程图、N-S图)进行描述。

8、模块设计的原则和方法

  • 清晰第一的设计风格。

  • 使用结构化的控制结构(顺序、选择、循环)。

  • 采用逐步细化的实现方法。

9、流程图与N-S图

  • 流程图:用菱形表示判定,箭头表示控制流向。

  • N-S图(纳-萨图):用矩形框表示控制结构,无箭头,结构更清晰。

Part IV 面向对象与UML

1、面向对象的基本特征

面向对象方法的核心特征包括:

  • 抽象:提取对象的共性,忽略与当前目标无关的细节。

  • 封装:将数据与操作封装在对象内部,隐藏实现细节。

  • 继承:子类继承父类的属性和方法,实现代码复用。

  • 多态:同一操作作用于不同对象时表现出不同的行为。

2、UML图的分类

UML(统一建模语言)图分为两大类:

静态图(结构图)

  • 用例图(Use Case Diagram)

  • 类图(Class Diagram)

  • 对象图(Object Diagram)

  • 构件图(Component Diagram)

  • 部署图(Deployment Diagram)

动态图(行为图)

  • 状态图(State Diagram)

  • 活动图(Activity Diagram)

  • 时序图(Sequence Diagram)

  • 协作图(Collaboration Diagram)

3、UML视图

UML提供了多种视图,用于从不同角度描述系统:

  • 用例视图:描述系统功能需求。

  • 逻辑视图:描述系统内部的逻辑结构。

  • 进程视图:描述系统的并发和同步机制。

  • 构件视图:描述系统的物理构件组织。

  • 部署视图:描述系统在物理节点上的部署情况。

4、UML的应用

UML广泛应用于软件开发的各个阶段:

  • 描述系统需求(用例图)。

  • 建立静态模型(类图、对象图)。

  • 描述系统行为(状态图、活动图、时序图)。

5、用例图与用例模型

参与者(Actor)

指与系统交互的外部实体,可以是人或其他系统。

用例(Use Case)

表示系统提供的一个完整功能,通常是一个业务流程。

用例规约

对用例的详细描述,包括前置条件、后置条件、主事件流、备选事件流等。

用例之间的关系

  • 包含关系(include):一个用例包含另一个用例的行为。

  • 扩展关系(extend):一个用例在特定条件下扩展另一个用例。

  • 泛化关系(generalization):子用例继承父用例的行为。

6、动态建模

时序图(Sequence Diagram)

  • 描述对象之间的交互顺序。

  • 强调消息发送的时间顺序。

协作图(Collaboration Diagram)

  • 描述对象之间的交互关系。

  • 强调对象之间的链接和消息传递。

区别

  • 时序图强调时间顺序。

  • 协作图强调对象之间的结构关系和交互链接。

Part V 需求工程与需求分析

1、什么是需求

需求是软件系统必须满足的条件或能力,包括:

  • 用户需求:用户为达成特定目标所期望的系统功能。

  • 业务需求:组织或客户为实现业务目标所需的功能。

  • 功能需求:系统必须提供的具体功能。

  • 非功能需求:如性能、安全性、可靠性、可用性等。

需求通常以合同、规范、说明书等形式明确下来。

2、需求工程(Requirements Engineering)

需求工程是指采用有效的技术和方法,使用合适的工具和符号,对目标系统的需求进行:

  • 获取

  • 分析

  • 描述

  • 验证

  • 管理

其目标是确保开发出满足用户真实需求的软件系统。

3、需求分析的步骤

需求分析通常包括以下几个步骤:

  1. 需求获取:通过与用户交流、调研、观察等方式收集需求。

  2. 需求建模:使用模型(如用例图、ER图、DFD图)对需求进行抽象和描述。

  3. 需求描述:编写《软件需求规格说明书》(SRS)。

  4. 需求验证:检查需求的完整性、一致性、可行性和可验证性。

  5. 需求管理:对需求变更进行控制与跟踪。

4、软件需求规格说明书(SRS)

SRS 是需求分析阶段的主要文档,内容包括:

  • 功能需求

  • 非功能需求

  • 系统接口

  • 用户界面

  • 数据需求

  • 运行环境

  • 假设与依赖

SRS 是后续设计、开发、测试和验收的依据。

5、需求分析的目标

  • 明确系统必须做什么。

  • 为系统设计提供基础。

  • 为项目验收提供标准。

  • 降低开发风险,避免需求变更带来的成本增加。

Part VI 面向对象分析

1 面向对象分析的核心

面向对象分析(OOA)以 用例模型 为主体,建立以下三类模型:

  • 类-对象模型:描述系统静态结构。

  • 对象-关系模型:描述对象之间的关联、依赖、泛化等关系。

  • 对象-行为模型:描述对象的动态行为、状态变化及交互过程。

2 分析类的三种原型

根据职责不同,将分析阶段识别的类划分为三种原型:

1
2
3
4
5
负责系统与外部参与者之间的交互,如 GUI、API、打印接口等。

封装一个用例或一项业务流程的控制逻辑,协调边界类与实体类完成特定任务。

表示系统中长期存在的信息及相关行为,通常对应业务实体,需持久化存储。

3 分析过程概要

  1. 根据用例图识别参与者和用例。

  2. 为每个用例绘制时序图(或协作图),确定消息流与所需对象。

  3. 从时序图中提取边界类、控制类、实体类。

  4. 建立类图:定义类属性、操作及类间关系(关联、泛化、依赖)。

  5. 建立状态图(可选):描述实体类对象的生命周期。

  6. 持续验证模型与需求的一致性,迭代求精。

4 类-对象模型示例要素

  • 类名:名词,首字母大写;尽可能使用业务术语。

  • 属性:类所维护的信息,可见性可暂时省略。

  • 操作:从用例行为或消息序列中抽象出的职责。

  • 关系:

    • 关联(Association):对象间的连接,可注明多重性。

    • 泛化(Generalization):继承关系,子类继承父类特征。

    • 依赖(Dependency):临时、单向使用关系。

5 对象-行为模型补充

  • 状态图 描述单个实体类对象的状态转换事件。

  • 活动图 描述用例或控制类的业务流程。

  • 时序图/协作图 细化对象间交互顺序与消息。

6 分析阶段交付物

  • 用例模型(用例图 + 用例规约)。

  • 类图(含边界类、控制类、实体类及其关系)。

  • 关键动态图(时序图、状态图、活动图)。

  • 分析模型说明书(可选,用于正式评审)。

Part VII 面向对象设计

1 设计目标

面向对象设计(OOD)在分析模型基础上,定义:

  • 如何构造系统;

  • 如何组织类与对象;

  • 如何满足非功能需求(性能、复用、可扩展、可维护等)。

2 模块与信息隐藏

1
2
3
具有明确定义的输入、输出和功能的程序实体,如类、包、构件。

模块内部数据与实现细节对外不可见,仅通过公共接口访问。

3 模块独立性度量

1
2
3
4
5
6
7
衡量模块内部元素彼此结合的紧密程度。\
理想:功能内聚 \> 顺序内聚 \> 通信内聚 \> 过程内聚 \> 时间内聚 \>
逻辑内聚 \> 偶然内聚。

衡量模块之间相互关联的强度。\
理想:非直接耦合 \< 数据耦合 \< 标记耦合 \< 控制耦合 \< 外部耦合 \<
公共耦合 \< 内容耦合。

4 设计任务总览

面向对象设计分为两大层次:

4.1 系统架构设计

  1. 高层架构设计:选择分层、MVC、微服务、客户端/服务器等总体结构。

  2. 确定设计元素:将分析类映射为设计类、包、子系统、构件。

  3. 任务管理策略:多线程/进程模型、并发控制、事务策略。

  4. 分布式机制:远程方法调用、消息队列、服务发现等。

  5. 数据存储方案:关系数据库、对象-关系映射、NoSQL、文件系统。

  6. 人机界面设计:界面框架、交互流程、可视化控件选型。

4.2 系统元素详细设计

  1. 类/对象设计:细化属性、操作签名、可见性、算法框架;应用设计模式。

  2. 子系统设计:定义子系统接口与协作契约,降低耦合。

  3. 包设计:按功能、层次、复用原则划分包,控制包间依赖。

5 类设计常用原则

  • 单一职责原则(SRP):一个类只负责一项职责。

  • 开闭原则(OCP):对扩展开放,对修改关闭。

  • 里氏代换原则(LSP):子类应能替换父类而不影响正确性。

  • 依赖倒置原则(DIP):依赖抽象,而非具体实现。

  • 接口隔离原则(ISP):客户端不应被迫依赖不用的接口。

6 设计模式速览

  • 创建型:Singleton、Factory Method、Abstract
    Factory、Builder、Prototype。

  • 结构型:Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy。

  • 行为型:Observer、Strategy、Template
    Method、Command、Iterator、State 等。

在详细设计阶段,可借助模式提高复用性与可维护性。

7 设计模型交付物

  • 细化类图(属性、操作、可见性、设计模式标注)。

  • 包图与子系统图(层次、接口、依赖)。

  • 关键动态图(时序图、协作图、状态图、活动图)。

  • 数据模型(类-表映射、ORM 配置、索引策略)。

  • 界面原型与交互说明(可选)。

  • 《软件设计说明书》(SDS)。

Part VIII 编码与测试

1 编码原则

  • 清晰第一:程序应易于阅读与理解。

  • 简洁直接:避免过度技巧与冗余逻辑。

  • 遵循团队编码规范(命名、缩进、注释、文件组织)。

  • 持续重构:保持代码"坏味道"最低。

2 测试基本概念

  • 定义:为发现错误而执行程序的过程。

  • 特点

    • 挑剔性:测试只能证明程序有错误,不能证明无错误。

    • 复杂性:输入空间、执行路径、并发状态极大。

    • 不彻底性:无法穷尽所有情况。

    • 经济性:在有限成本下尽可能暴露高价值缺陷。

3 测试级别(V模型对应)

  1. 单元测试(Unit Testing)

  2. 集成测试(Integration Testing)

  3. 确认测试(Validation Testing)

  4. 系统测试(System Testing)

  5. 验收测试(Acceptance Testing)

4 测试方法分类

4.1 静态分析(不执行程序)

  1. 静态分析器:自动检查语法、类型、安全漏洞、编码规范。

  2. 代码评审:走查(Walkthrough)、审查(Inspection)、结对评审。

4.2 动态测试(执行程序)

  1. 黑盒测试:基于需求规格,不关心内部结构。

    • 等价类划分、边界值分析、决策表、因果图、状态测试、场景测试。
  2. 白盒测试:基于程序内部逻辑结构。

    • 逻辑覆盖:语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖、路径覆盖。

5 逻辑覆盖强度等级(由弱到强)

  1. 语句覆盖(Statement Coverage)

  2. 判定覆盖(Branch Coverage)

  3. 条件覆盖(Condition Coverage)

  4. 判定/条件覆盖(Branch/Condition Coverage)

  5. 条件组合覆盖(Multiple Condition Coverage)

  6. 路径覆盖(Path Coverage)

6 测试用例设计模板

  • 用例编号、测试项、优先级、前置条件、输入、操作步骤、预期结果、实际结果、是否通过、备注。

7 回归测试与自动化

  • 每次修改后重新执行已有测试,防止引入新缺陷。

  • 对稳定模块编写自动化测试脚本(单元、接口、UI),形成持续集成流水线。

8 调试(Debugging)

  • 目标:定位并消除已发现错误的根源。

  • 常用策略:断点、单步、打印日志、回溯分析、二分定位、因果推理。

9 测试交付物

  • 测试计划(Test Plan)

  • 测试用例与脚本(Test Case / Script)

  • 缺陷报告(Bug Report)

  • 测试总结报告(Test Summary Report)


当时还是2023年秋天。