软件工程
40 分 :25 单选 15 判断
软件工程
第一章 软件工程学概述
软件危机
软件危机包含下述两方面的问题
- 如何开发软件,以满足对软件日益增长的需求;
- 如何维护数量不断膨胀的已有软件
定义
在计算机软件的开发和维护过程中所遇到的一系列严重问题。
典型表现
- 开发成本和进度估计不准确
- 用户对完成的软件系统不满意
- 软件产品质量靠不住
- 软件不可维护
- 没有适当的文档资料
- 软件成本在计算机系统成本中占比上升
- 软件开发生产效率的提高追不上计算机普及的深入
产生原因
- 规模加大,复杂性提高
- 不同于硬件,缺乏可见性,维护即要修改原来的设计
- 技术手段和管理方法缺乏
- 用户和开发人员的鸿沟
- 不同于一般程序,规模庞大多人分工
- ……
- 软件开发工作量
- 编写 10%-20%
- 测试 40%-50%
- 运行维护:长期,费用占 55%-70%
- 软件配置:程序、文档、数据
- 软件开发最主要的失败原因:对客户的需求没有全面理解
- 软件开发的修改成本:在中期剧增
消除途径
- 消除错误观念:“软件就是程序”
- 正确认识软件是程序、文档和数据的完整集合
- 软件是产品,软件开发是工程项目
- 推广使用成功的软件开发技术和方法
- 软件工具和软件工程支撑环境
软件工程
概念
采用工程的概念、原理、技术、方法来开发和维护软件,把经过时间考验而证明正确的管理技术和当前能够得到的最好技术方法结合起来,以经济地开发出高质量的软件并有效地维护它。
本质特性
- 注重大型程序的构造
- 中心课题是控制复杂性
- 软件经常变化
- 开发效率非常重要
- 和谐开发合作
- 软件必须有效地支持他的用户
- 在软件工程领域中通常由具有一种文化背景的人替具有另一种文化背景的人创造产品
基本原理
(好像不重要)
- 分阶段的生命周期
- 坚持进行阶段评审
- 严格的产品控制
- 采用现代化程序设计技术
- 结果应能清楚地审查
- 开发小组人员少而精
- 承认不断改进软件工程的必要性
软件工程方法学(泛型)
好像不重要
在软件生命周期全过程中使用的一整套技术方法
- 三要素:方法、工具、过程
- 方法
- 传统方法学
- 生命周期方法学或结构化泛型
- 采用结构化技术
- 面向行为或面向数据
- 面向对象方法学
- 以数据为主线,封装数据和对数据的操作
- 传统方法学
软件生命周期
软件生命周期由软件定义、软件开发和运行维护(也称为软件维护)3 个时期组成,每个时期又进 步划分成若干个阶段
阶段
- 定义时期
- 问题定义、可行性研究、需求分析
- 开发时期:
- 系统设计:总体设计、详细设计
- 系统实现:编码和单元测试、综合测试
- 维护时期:
- 软件维护:改正性维护、适应性维护、完善性维护、预防性维护
每个阶段的基本任务
- 问题定义
- 要解决的问题是什么?
- 确定客户的问题性质,工程目标和工程规模
- 可行性研究
- 问题是否有可行的解决办法?
- 经济、技术、法律可行性 → 第二章
- 需求分析
- 目标系统必须做什么?
- 确定系统必须具备的功能、性能,产生规格说明书 → 第三章
- 总体设计(概要设计)
- 应该怎样实现目标系统?
- 推选设计方案及其详细计划,确定程序模块间的关系 → 第五章
- 详细设计
- 怎样具体地实现系统?
- 也叫模块设计,详细设计每个模块,确定实现模块功能需要的算法和数据结构 → 第六章
- 这个阶段的任务还不是编写程序,而是设计出程序的详细规格说明(类似工程蓝图)
- 编码和单元测试
- 仔细编写、测试每一个模块 → 第七章
- 综合测试
- 集成测试(装配后测试)、验收测试(用户参与测试) → 第七章
- 软件维护
- 通过各种必要的维护活动使系统待久地满足用户的需 → 第八章
- 改正性维护、适应性维护、完善性维护、预防性维护
软件过程
生命周期模型(过程模型):描述软件过程,规定了把生命周期划分成哪些阶段和各个阶段的执行顺序。
典型的过程模型
瀑布模型
文档驱动型,适合小规模软件
- 特点
- 阶段间具有顺序性和依赖性(各阶段依次进行)
- 推迟实现(尽可能推迟物理实现)
- 质量保证(每个阶段完成文档,并进行审核)
- 优点:强迫开发人员采用规范方法,文档驱动降低维护成本
- 缺点:前期没产品,无法应对改进的需求
快速原型模型
取得客户满意的原型再做规格说明书,无反馈环
- 快速原型可以取代规格说明阶段,但不是设计阶段
- 较好适应客户需求描述不完全或不确定的情况,减少返工
- 开发人员在建立原型中得到经验,减少犯错的可能
- 原型在得到用户确认后会被抛弃,但界面等可以得到保留
- 优点:快速、经济,适合招标
增量模型(渐增模型)
将软件拆分成构件逐步交付客户
完成需求分析规格说明和概要设计后,将软件看作增量构件的组合
从核心构件开始逐渐集成软件(但必须是可测试的)
优点
- 逐步增加功能
- 用户有较充裕的时间学习和适应新产品,减少新产品给客户带来的心理影响
- 能在较短时间内向用户提交可完成部分工作的产品
- 分阶段交付产品
- 适应需求变化
缺点:需要一个开放结构,方便构件加入;开发人员需要协调软件的整体性和构件的独立性
螺旋模型
以瀑布和快速原型为基础,每个阶段前都增加风险分析
- 优点
- 适合内部开发的大规模软件
- 风险驱动,比快速原型更好的控制各类风险(也可能是它的一个弱点)
- 缺点:开发人员需要有风险意识和经验
喷泉模型
喷泉模型体现了面向对象开发过程迭代和无缝连接的特性
- 将线性过程作为总目标
- 对开发活动进行迭代求精,不同阶段无明显边界
Rational 统一过程 RUP
最佳实践
6 个开发经验:迭代开发、管理需求、使用基于构件的体系结构、可视化建模、验证软件质量、控制软件变更
RUP 软件开发生命周期
- 核心工作流
- 6 个核心过程工作流程、3 个核心支持工作流程
- 4 个工作阶段:
- 初始阶段(建立业务模型,定义产品视图,确定项目范围)
- 精化阶段(确定体系结构,制定项目计划,确定资源需求)
- 构建阶段(开发构件和应用程序、集成并测试)
- 移交阶段(将开发的产品提交用户使用)
敏捷过程
客户密切合作、快速响应
- 个体和交互胜过过程和工具:构建开发团队,再配置过程和工具
- 可以工作的软件胜过面面俱到的文档:文档尽可能精简
- 客户合作胜过合同谈判:开发团队和客户密切合作
- 相应变化胜过遵循计划:计划具备可塑性
极限编程
敏捷过程的一种,适合需求模糊且经常改变的场合
第二章 可行性研究
可行性研究的任务
可行性研究:研究问题是否值得解决,而非解决问题
目的:用最小的代价在尽可能短的时间内确定问题是否能够解决。
可行性研究的任务
- 技术可行性:有技术实现?
- 经济可行性:经济效益超过开发成本?
- 操作可行性:系统的操作方式在用户组织内是否可行?
- 法律、社会效益可行性
根本性任务:对以后的行动方针提出建议。
可行性研究过程
- 复查系统规模和目标
- 研究目前正在使用的系统
- 导出新系统的高层逻辑模型(数据流图、数据字典)
- 进一步定义问题
- 导出和评价供选择的解法
- 推荐行动方针、草拟开发计划、书写文档提交审查……
✔️ 数据流图
数据流图 OFD:逻辑模型,分层次的描绘方法便于读者从抽象到具体逐步深入了解系统。
- 描绘信息和数据从输入移动到输出过程中所经受的变化
- 只描绘数据在软件流动和被处理的逻辑过程
- 数据存储和数据流是数据的静态和动态表现
- 数据的符号表示(* + ⊕)不会考吧
数据库的写入写出流可以不写名字
变换流:一般的
事务流:有分类的
父子图平衡、数据守恒
数据字典
逻辑模型:数据流图 + 数据字典
定义数据的方法:
- 顺序:确定顺序的连接分量,如 D=A+B+C
- 选择:标所多个元素中取一个,如 G=[D|E|F]
- 重复:将分量重复若干次,如 H=3{G}5 表示 G 重复 3 到 5 次
- 可选:重复零到一次,如 I=(H)
第三章 需求分析
需求分析的任务
需求分析:系统必须做什么?定义时期最后一个阶段,产生软件需求规格说明书。
确定对系统的综合要求
- 功能需求:系统必须提供的服务
- 性能需求:系统必须满足的定时约束和容量约束
- 可靠性和可用性需求:系统的可靠性(重启,出错等)
- 出错处理需求:系统对环境错误的处理和响应(别的系统或者环境错了)
- 接口需求:系统与环境的通信格式
- 约束:设计和实现时需要遵守的限制(语言限制、硬件平台限制)
- 逆向需求:软件系统不该做什么
- 将来可能提出的要求:据分析未来很可能出现的需求
然后是……
分析系统的数据要求
导出系统的逻辑模型
修正系统开发计划
与用户沟通获得需求的方法
与用户沟通获得需求的方法 P59:
- 访谈:正式、非正式访谈;调查表、情景分析技术
- 面向数据流自顶向下求精:(结构化分析)把数据流图中数据流和数据存储定义到元素级
- 简易的应用规格说明技术:面相团队,客户和开发人员密切合作(开需求分析会)
- 快速建立软件原型:快速建立用于演示目标系统功能的模型
分析建模与规格说明
应该不考
结构化分析 SD:面向数据流自顶向下,逐步求精进行需求分析的方法。
实质上是一种创建模型的活动:实体 - 联系图、数据流图、状态图
验证软件需求
验证软件需求 P70:
- 一致性:需求与需求不矛盾。采用形式化需求陈述语言书写
- 完整性:规格说明书包括所有用户需要的功能和性能。使用原型系统,和客户密切合作。
- 现实性:需求的软件硬件实现现实性。根据过往开发经验。必要时使用仿真技术
- 有效性:需求能有效解决用户面对的。使用原型系统,和客户密切合作
第五章 总体设计
总体设计(概要设计、初步设计):概括的说,系统应当如何实现。划分出组成系统的物理元素,并设计软件的结构,设计数据库并制定测试计划。
设计过程
系统设计阶段 + 结构设计阶段
- 设想供选择的方案:从数据流图出发,抛弃技术不可行的方法
- 选择合理的方案:低、中、高成本三套方案,并提供系统流程图、物理元素清单、成本效益分析、实现系统的进度计划
- 推荐最佳方案:综合利弊推荐最佳方案,制定详细计划
- 功能分解:将复杂的功能分解,使每个功能对程序员明显易懂
- 设计软件结构:把模块组织成良好的层次系统,顶层调用下层实现
- 设计数据库:详见数据库课程
- 制定测试计划:尽早考虑测试问题,详见第七章
- 书写文档:系统说明、用户手册、测试计划、详细的实现计划、数据库设计结果
- 审查和复查:严格审查,客户复审
设计原理
- 模块化:把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能。把模块集成在一起又能满足客户需求。模块化程度适中开发成本最低(接口成本)
- 抽象:用层次的方式构造和分析
- 逐步求精:将精力放在当前开发阶段的重点上,稍后处理其他必要细节
- 信息隐藏和局部化:模块内部信息独立于其他模块而不可被访问;将关系密切的软件元素物理上彼此靠近
- 模块独立:高内聚,低耦合
耦合:(好、低)数据 < 控制 = 特征 < 公共环境 < 内容(不好、高)
- 数据耦合:模块通过参数交换数据
- 控制耦合:模块通过参数交换控制信息(可分解模块转化为数据耦合)
- 特征耦合:模块接收的参数数据结构中有冗余数据信息(访问权限漏洞)
- 公共环境耦合:多个模块共用数据环境(全局变量)
- 内容耦合:访问模块内部数据、不正常访问、代码重叠、多入口
内聚:(好、高)功能 > 顺序 > 通信 > 过程 > 时间 > 逻辑 > 偶然(不好、低)
- 偶然内聚:一组没有完整功能的语句巧合地被多次使用
- 逻辑内聚:不同功能的语句混在一起,共用部分代码
- 时间内聚:语句在同一段时间内执行
- 过程内聚:模块内元素相关,且以特定顺序执行
- 通信内聚:模块使用同一个输入产生同一个输出
- 顺序内聚:模块处理元素和同一功能密切相关,且顺序执行
- 通常一个处理元素的输出数据作为下一个处理元素的输入数据
- 功能内聚:模块所有元素属于同一整体,完成单一功能
启发规则
改进软件结构提高模块独立性:高内聚低耦合
模块规模适中:模块复杂和借口复杂折衷
深度、宽度、扇出和扇入适当:
- 深度:软件结构中控制的层数
- 宽度:一层中模块总数的最大值
- 扇出:一个模块直接调用的模块数
- 扇入:一个模块被上级调用的模块数
模块的作用域应该在控制域之内:
- 控制域:自身和直接或间接从属模块的集合
力争降低模块接口的复杂度:参数和返回值应当简单且易理解
设计单入口单出口模块:不要随意 return
模块功能要可预测:相同输入对应相同输出
面向数据流的设计方法
变换流:数据从外部进入软件系统,经处理后离开系统进入外部
事务流:数据到达一个处理后根据输入类型从若干个动作中选取一个执行
第六章 详细设计
详细设计:确定应该怎么具体实现所要求的系统。不仅要保证逻辑上正确实现每个模块的功能,更要保证处理过程尽可能简明易懂。
结构程序设计
结构程序设计:仅通过顺序、选择和循环控制结构连接,且每个代码块只有一个入口,一个出口(五要素)
- 经典结构程序设计:顺序、IF-ELSE、DO-WHILE
- 扩展结构程序设计:CASE、DO-UNTIL
- 修正结构程序设计:LEAVE、BREAK
过程设计工具
过程设计工具 P124-129:大题
- 程序流程图
- 不是逐步求精的好工具,诱导程序员过早考虑控制流程
- 允许随意转移数据,不受约束
- 不易表示数据结构
- 盒图(NS 图)
- 功能域明确
- 不能任意转移控制
- 容易确定数据的作用域
- 容易表现嵌套关系,体现层次结构
- PAD 图
- 设计产生的必然是结构化程序
- 程序结构清晰,竖线总条数即程序层次数
- 表现程序逻辑,易读易懂易记
- 易于转化为高级语言
- 可以表示程序逻辑,也可以表示数据结构
- 支持自顶向下逐步求精的方法
- 判定表、判定树
✔️ 程序流程图
基本符号
控制结构
扩展符号
例
✔️ 盒图
基本符号
示例
特点
- 不允许随意转移控制
- 局部及全程数据的作用域易见
- 易表现嵌套关系以及模块的层次结构
✔️ PAD 图
问题分析图 (Problem Analysis Diagram, PAD)
日立公司,1973
示例
特点
- 支持逐步求精的设计思想
- 容易将 PAD 自动转换为高级语言源程序
✔️ 判定表,判定树
表示复杂条件组合与动作之间的对应关系
一张判定表由 4 部分组成
- 左上部列出所有条件
- 左下部是所有可能做的动作
- 右上部是表示各种条件组合的一个矩阵
- 右下部是和每种条件组合相对应的动作。
示例:航空行李托运费计算
- 按规定:重量不超过(包括)30 公斤的行李可免费托运。重量超过 30 公斤时,对超运部分,头等舱国内乘客收 4 元/公斤,其它舱位国内乘客收 6 元/公斤;外国乘客收费为国内乘客的 2 倍。
判定表:
判定树:
程序复杂度的定量度量
环形复杂度:度量程序复杂度的一种方法。
- 线性无关的区域数(即离散中平面图面数)
- 边数 - 节点数 +2
- 判定节点数 +1
第七章 实现
实现:编码 + 测试。软件测试工作量占开发的 40% 以上,安全软件更多。
编码
选择程序设计语言
除了选择适宜的程序设计语言外,也要考虑以下因素
- 系统与用户的要求:客户限制
- 可以使用的编译程序:目标环境限制编译程序
- 可以得到的软件工具
- 工程规模:规模过大可以自己设计语言(书上观点)
- 程序员的知识:技术栈
- 软件可移植性要求
- 软件的应用领域:科学计算、Web 开发等
编码风格
- 程序内部文档:变量命名、模块注解、代码注解、程序清单的布局
- 数据说明:数据结构和用途的说明
- 语句构造:避免写一行、避免非常复杂的条件测试、避免大量嵌套等
- 输入输出:对输入做合法性检验,设计良好的输出报表等
- 效率:程序运行时间、存储器效率、输入输出效率
软件测试基础
软件测试的目标
软件测试:为了发现程序中的错误而执行程序的过程
软件测试的目的:在软件投入生产性运行之前,尽可能多地发现软件中的错误
- 测试是为了发现程序中的错误
- 好的测试方案极可能发现迄今为止未发现的错误
- 成功的测试是发现了迄今为止未发现的错误的测试
软件测试准则
可能蛮重要的
- 所有测试都应该能追溯到用户需求
- 远在测试开始前制定测试计划(需求分析阶段)
- 把 Pareto 原理应用到软件测试中
- Pareto 原理:80% 的错误来自 20% 的模块
- 从小规模测试开始逐步到大规模测试
- 穷举测试是不可能的
- 为了达到最佳的测试效果,应该由独立的第三方从事测试工作
测试方法
✔️ 黑盒测试
已经知道产品应该具有的功能,通过测试验证每个功能是否正常使用
等价划分
边界值分析
✔️ 白盒测试
知道产品内部工作过程,通过测试检验内部动作是否按照规格说明书正常进行
语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖
测试步骤
- 模块测试(单元测试):验证每个模块作为一个单元能正确运行
- 子系统测试:将模块组成子系统测试,着重测试模块的接口
- 系统测试:子系统组成系统测试需求和功能,寻找需求说明的错误和软件总体设计错误
- 验收测试(确认测试):将软件实体作为单一实体测试,在用户积极参与下进行
- 平行运行:同时运行新系统和旧系统比较差异
单元测试
(P153)
检测软件设计的最小单元—模块
测试重点
模块接口、局部数据结构、重要执行通路、出错处理通路、边界条件
代码审查
单元测试由组长、设计者、编写者、测试者建立审查小组测试
计算机测试
编写驱动程序测试模块,代替模块接口进行测试
集成测试
子系统测试 + 系统测试
将模块组装成程序的两种方法:非渐增式测试方法、渐增式测试方法
非渐增式测试
分别测试每个模块,按设计一次性集成
- 对模块做单元测试
- 将所有模块组装在一起
- 将组装后的程序作为整体进行测试
缺点:无错误隔离手段,主要设计错误发现迟
渐增式测试
逐步把下一被测模块同已测好的那些模块进行集成
将单元测试和集成测试组合起来,把下一个要测试的模块同已经测试好的那些模块结合起来进行测试
自顶向下集成:
步骤
- 用存根程序代替直属控制模块
- 根据树的 dfs 序或 bfs 序进行集成
- 逐步加入新的模块,可能需要进行回归测试
优点
- 错误隔离;
- 不需要驱动程序;
- 早期就可以验证程序功能;
- 较早发现接口错误
缺点
- 需要存根程序(桩模块)
- 低层错误可能很晚才能发现
回归测试:加入新模块后将原有的测试再做一遍
自底向上集成:
步骤
- 根据树的逆 bfs 序进行集成
- 将底层模块组成簇,编写驱动程序测试
- 去掉驱动程序,将上层模块加入进来,簇合并
优点
- 错误隔离;
- 可复用模块得到充分测试;
- 不需要存根程序
缺点
- 需要驱动程序;
- 主要设计错误发现迟;
- 验证系统功能迟
三明治式集成(混合式集成)
步骤
- 确立一个模块层为界限
- 上层使用自顶向下策略
- 下层使用自底向上策略
优点
- 集大成,减少了驱动模块和存根程序的开发
- 错误隔离
- 能较早的发现设计缺陷
- 操作模块得到成分测试,可以信任的复用
缺点:中间层的测试非常晚
三者比较
确认测试
定义(也叫验收测试):验证软件的有效性,即符合用户的功能和性能需求。用户积极参与,通常使用黑盒测试方法。
- 软件配置复查:软件配置齐全符合要求;文档和程序一致;手册正确性完整性
- Alpha 测试:用户在开发者的场所进行,在开发者指导下进行测试
- Beta 测试:最终用户在客户场所进行,开发者不在场,但记录测试过程中的问题
调试
调试:在测试发生错误后排除错误的过程(艰巨的脑力劳动)
调试途径
- 蛮干法:输出日志,并查找问题
- 回溯法:人工沿控制流回溯源码
- 原因排除法:对分查找法、归纳法、演绎法
第八章 维护
第八章 自学内容
软件维护的定义
软件维护:在软件已经交付使用后,为了改正错误或满足新的需要而修改软件的过程。
- 改正性维护:诊断和改正错误的过程,17%~21%
- 适应性维护:为了和变化的环境适当配合而进行的修改软件活动,18%~25%
- 完善性维护:增加用户提出的新功能或修改已有功能,50%~66%
- 预防性维护:为未来的改进奠定良好的基础,4% 左右
完善»适应>=改正>其他
软件维护的特点
- 结构化维护与非结构化维护的差别巨大
- 结构化维护:完整的软件配置(文档、测试等)减少了精力浪费并提高了维护的总体质量
- 维护代价高昂:甚至达到预算的 70-80%
- 维护的问题多
- 理解他人代码的困难
- 文档资料不足
- 开发人员可能已经调离
- 设计时未考虑将来的修改
- 软件维护不是吸引人的工作
软件的可维护性
决定软件可维护性的因素:
- 可理解性:功能、接口、内部处理逻辑;模块化、文档、语言
- 可测试性:可用的测试、调试工具
- 可修改性:耦合、内聚、信息隐藏、局部化、控制域与作用域的关系
- 可移植性:硬件环境移植的难题程度
- 可重用性:可重用构件越多,测试的可靠性越高,维护的精力越少
第九至十一章 面向对象方法学
面向对象方法学概述
OO = objects + classes + inheritances + communication with messages
面向对象 = 对象 + 类 + 继承 + 消息通信
- 对象:客观世界由对象组成,复杂的对象由简单的对象组成
- 类:将对象划分成对象类,定义属性和方法
- 继承:子类具有和基类相同的属性或方法
- 消息传递:对象间通过传递消息相互联系
面向对象方法学的优点
- 与人类思维习惯一致
- 稳定性好:以对象为中心构造系统
- 可重用性好:数据和操作是平等的;对象类可重复使用
- 较易开发大型软件产品
- 可维护性好:易改易维护易调试易理解
在 UML 术语中 “类” 的实际含义是 “一个类及属于该类的对象”。
- 对象模型:类图
- 功能模型:用例图
- 动态模型:顺序图、状态图
面向对象建模
三种模型
- 功能模型:系统功能(指明系统应该 “做什么”)。数据流图或用例图
- 对象模型:静态的、结构化的系统的数据结构:类图、对象图(最重要、最基本、最核心)
- 动态模型:系统的控制结构:活动图、状态图、顺序图等
✔️ 用例图
- 描述外部行为者 (actor) 所理解的系统功能
- 系统、行为者、用例及用例之间的关系
定义
- 系统
- 提供用例的黑盒
- 边界用于划定系统的功能范围
- 行为者(Actor)
- 与系统交互的人或其它系统
- 用例(Use Case)
- 行为者感受到的一个完整功能
- 实现一个具体的用户目标
- 向行为者提供可识别的值
步骤
- 确定系统边界
- 确定行为者:角色/参与者
- 确定用例
- 简述行为者和用例
- 用例描述
确定行为者
行为者总在系统外,不是系统的一部分
可能的行为者
- 谁使用系统
- 谁维护系统
- 谁启动或关闭系统
- 谁从系统获取信息
- 谁为系统提供信息
- 是否有事情自动在预计时间发生
确定用例
- 行为者希望系统提供什么功能
- 行为者 CRUD 什么信息
- 系统给行为者通知什么信息
- 系统需要从行为者那得到什么信息
- 系统的启动、关闭、维护等
简述行为者和用例
用例描述
完成用例功能需要的步骤
- 基本路径
- 可选路径
- 用例描述模板
基本路径
基本路径 (快乐场景) :运转正常时,使用用例的步骤
可选路径
用例描述模板
用例模型结构
- 包含(Include)
- 扩展(Extend)
- 继承(Inheritance)
包含
- 多个用例可以重用的行为段
- 包含是无条件的
扩展
- 有条件地扩展已有用例的行为
- 在不改变原始用例的情况下增加用例行为
继承
- 种属关系
- 可以于行为者和用例
- 偏重修改的意味
✔️ 类图
类间关系
关联(Association)
聚集(Aggregation)
泛化(Generalization)
示例
✔️ 顺序图
- 按第一次动作的时间顺序安排协作对象
- 为每一个消息添加信息链和活动条
- 对每一个活动重复第 2 步操作
✔️ 状态图
描绘对象的状态及引起状态迁移的事件,来表示对象的行为
- 状态:对象满足某些条件、执行某些活动或等待某些事件。
- 初态、终态和中间状态
- 活动:对象达到某种状态时所做的处理
- 事件:在某个特定时刻发生的事情,引起状态迁移
- 迁移:两个状态间的一种关系。当对象处于一个状态时,在特定事件发生并且特定条件满足时,执行一定动作并进入第二个状态
符号
示例
画状态图
例
指向自己的是事件
指出去的是活动
面向对象设计
第十一章
面向对象设计的任务
- 系统设计:确定实现系统的策略和目标系统的高层结构
- 对象设计:确定解空间中的类、关联、接口形式及实现服务的算法
面向对象设计准则
- 模块化
- 抽象
- 信息隐藏
- 弱耦合(跟之前不一样)
- 交互耦合:对象通过消息连接来实现耦合(应尽可能松散、参数少而简单)
- 继承耦合:基类和派生类的耦合(应保持紧密)
- 强内聚
- 服务内聚:一个服务完成且仅完成一个功能
- 类内聚:一个类有且仅有一个用途
- 一般 - 特殊(层次)内聚:符合多数人的观念
- 可重用
启发规则
提高面向对象设计质量的启发规则 P261:
- 设计结果清晰易懂
- 一般 - 特殊结构深度适当:类层数 7 ± 2
- 使用简单的协议:参数少
- 使用简单的服务:避免一个方法太复杂
- 把设计变动减至最小
软件重用
软件重用层次
- 知识重用,如软件工程知识的重用
- 方法和标准重用,如开发方法或国标
- 软件成分重用
- 代码重用:源代码剪贴、源代码包含、继承
- 设计结果重用:设计模型的重用
- 分析结果重用:需求模型的重用
类构件的重用方式
- 实例重用:多个对象用同一个实例;一个复杂的类由多个简单的类创建
- 继承重用:利用继承性对类构件进行剪裁
- 多态重用:利用多态性使对外接口更具一般性
测试策略
应该不用
面向对象软件不存在层次的控制结构,传统的自顶向下和自底向上集成策略没有意义。
集成测试方法:
- 基于线程的测试:把相应系统的一个输入或事件需要的类集成分别进行测试和回归测试
- 基于使用的测试:把独立类测试完成后再测试依赖类直至测试完成
软工设计图
以下总结仅供参考。
数据流图 ☆
https://www.bilibili.com/video/BV1Jt411d7nR?p=3
父子图平衡、子图内平衡
- 顶层图:整个软件系统看作一个大的加工,确定软件的数据源点和终点、源点和终点与软件系统之间的输入/输出数据流
- 零层图、一层图
NS 图(盒图)
PAD 图
判定表
判定表化简
判定树
用例图 ☆
用例:椭圆,描述从行为者看到的系统全部完整的功能(存款而非插卡输密码等)
- 行为者希望系统提供什么功能
- 行为者必须的增删改查的功能
- 系统给行为者的通知
- 系统从行为者得到的信息
系统边界:黑色方框,用于划定系统的功能范围
行为者:小人,位于系统外和系统进行交互的人和系统;
用例:功能
包含、使用:A 使用 B 的功能,描述一种必然性
- 销户/下单、结算/搜索商品
- 每次都必须做,先做什么才能做什么
扩展:A 扩展出了 B 的功能,B 用到了 A 的功能,描述一种可能性
- 注册/短信提醒、登录/停机提醒
- 额外可能做的功能,通常是扩展(登录发现没注册)。
- 新功能用老功能,通常是扩展(停机提醒用短信提醒)
- 只能额外做操作,不能修改
继承、泛化:A 继承基类 B
- 空心三角箭头:管理员 → 用户
修改了原有的某些功能。做了不一样的东西
✔️ 白盒测试(结构测试、逻辑驱动测试)
语句覆盖
语句覆盖(点覆盖):测试数据需要覆盖所有语句
判定覆盖
判定覆盖(边覆盖):测试数据满足所有的判定结果(即每个判定的 TF 结果都要走过)
条件覆盖
条件覆盖:将判定中的判定子句的所有 TF 都走过(只看条件,可能大判定 TF 没都走)
判定/条件覆盖
判定/条件覆盖:满足判定 + 条件覆盖
条件组合覆盖
条件组合覆盖(多重条件覆盖):将所有判定的子句 TF 的组合都走过,但不同判定之间无关联
路径覆盖
路径覆盖:将每条可能的路径至少执行一次,如有循环至少进入一次
条件组合覆盖 覆盖 判定/条件覆盖
判定/条件覆盖 覆盖 判定覆盖和组合覆盖
✔️ 黑盒测试
功能测试、数据驱动测试
等价类:有效等价类、无效等价类
设计测试用例:
- 有效的:尽可能多的覆盖未覆盖的有效等价类,直至覆盖全部
- 无效的:一次只覆盖一个,直至覆盖全部
设计等价类表:
设计有效类测试用例
设计无效类测试用例
边界值分析
类图 ☆
类图属于对象模型,描述类及类与类之间的静态关系
- public +
- private –
- protected #
重数:0..1,0..,1..,1..15,3
一元关联:学生管理学生
导航:箭头,表示使用到对象
关联类:
限定关联:
聚集关系:菱形表示
组合:(公司和部门)强依赖删除父类,则所有子类失去意义
聚合:(部门和员工)弱依赖,由什么组成
组合(强) 聚合(弱)
泛化:
依赖:
顺序图(事件跟踪图)
顺序图描述对象之间动态的交互关系
状态图 ☆
借书 (n)[n<10]/n=n+1
组合状态
顺序图改状态图:
- 射入线:状态图中的事件。
- 射出线:状态图中的状态的行为。
- 两个事件之间的间隔就是一个状态。
二进制转换,输入输出题目描述 - 简单二进制这回你的任务很简单,就是简单的数数,不过是在二进制下计算哦,计算一个十进制数的二进制包含多少个 1.
如 3 的二进制是 11,则包含 2 个 1,2 的二进制是 10,则包含 1 个 1.解答要求时间限制:1000ms, 内存限制:100MB 输入输入包含多组测试,
每组测试输入一个整数 n(0≤ n <65535),输入到文件末尾结束。输出输出 n 的二进制含有 1 的个数,每组测试占一行。样例输入样例 1 复制 310 输出样例 122