软工二总复习
第一、二章
1. 名词解释:软件工程
IEEE 对软件⼯程定义为:
- 应⽤系统的、规范的、可量化的⽅法开发、运⾏和维护软件,即将⼯程应⽤到软件。
- 对1.中各种⽅法的研究。
2. 从1950s-2000s之间的各种特点
1950s:科学计算;以机器为中心进行编程;像生产硬件一样生产软件。
1960s:业务应用(批量数据处理和事物计算);软件不同于硬件;用软件工艺的方式生产软件。
1970s:结构化方法;瀑布模型;强调规则和纪律。它们奠定了软件工程的基础,是后续年代软件工程发展的支撑。
1980s:追求生产力最大化;现代结构化方法/面向对象编程广泛应用;重视过程的作用。
1990s:企业为中心的大规模软件系统开发;追求快速开发、可变更性和用户价值;web应用出现
2000s:大规模web应用;大量面向大众的web产品;追求快速开发、可变更性、用户价值和创新。
第四章 项目启动
1. 如何管理团队
采取哪些方法
- 建立团队章程
- 持续成功
- 和谐沟通
- 避免团队杀手
团队结构有几种?
- 主程序员团队:决策需要由主程序员进行制定
- 效率高,如果完成把握大,并且需要时间紧迫,可以优先考虑
- 一个人的决断容易影响整个团队,如果项目复杂,主程序员会成为瓶颈。
- 适用于把握性大,时间要求紧的情况
- 民主团队:没有集中的瓶颈,成员发挥能动性,工作效率降低,冲突解决。敏捷+较有挑战性的项目
- 开放团队:
- 为了创新而存在的。黑箱管理,问题在于项目进展没有可视度。
- 相对于前两个团队的需求明确,团队的需求并不明确
- 管理者主要负责清除出现的障碍。
- 开放团队是为了创新而存在
2. 质量保障有哪些措施
里程碑——质量保障活动
需求开发——需求评审、需求度量;
体系结构——体系结构评审、集成测试(持续集成);
详细设计——详细设计评审、设计度量、集成测试(持续集成);
实现——代码评审、代码度量、测试(测试驱动和持续集成);
测试——测试、测试度量。
要及时的根据保障计划进行质量验证,质量验证的方法主要有评审、度量、测试三种。
3. 配置管理有哪些活动
- 标识配置项:确定应该被保留的部分,并且给予他们确定标识,包含配置项的特征,包括生产者、基线建立时间、使用者等。
- 版本管理:为配置项赋予版本号,管理分支和多版本情况。
- 变更控制:以可控、一致的方式进行变更处理,包括对变更的评估、协调、批准或拒绝、实现和验证。
- 配置审计:验证配置项的完整性、正确性、一致性和可追踪性。
- 状态报告:反映当前的配置状态。
- 软件发布管理:将配置项发布到开发活动之外,例如发布给客户。
第五章 需求基础
1. 名词解释:需求
IEEE对需求的定义为:
- ⽤户为了解决问题或达到某些⽬标所需要的条件或能⼒
- 系统或系统部件为了满⾜合同、标准、规范或其它正式⽂档所规定的要 求⽽需要具备的条件或能⼒
- 对⑴或⑵中的⼀个条件或⼀种能⼒的⼀种⽂档化表述。
2. 需求的三个层次
业务需求(Business Requirement)
业务需求是高层次的解决方案和系统特性、系统开发的战略出发点、高层次的需求,描述为什么要开发系统。
在系统使用 3 个月后,销售额度应该提高 20%(期望,没有从软件角度进行描述,业务需求)
可以建⽴⾼层次的解决⽅案,其系统特性如SF1~SF4所示(system feature)。
- SF1:管理VIP顾客信息。
- SF2:提供VIP顾客服务,增加回头率。
- SF3:使⽤多样化的特价⽅案,吸引顾客购买,增加销售额。
- SF4:使⽤多样化的赠送⽅案,吸引顾客购买,增加销售额。
用户需求(User Requirement)
执行具体任务的用户对系统所能完成任务的期望,描述了系统能帮用户做什么(直接用户、间接用户)
特性:
- 模糊、不清晰(允许适度的⽤形容词和副词)
- 多特性混杂 (功能和⾮功能的混杂)
- 多逻辑混杂 (⼀个任务需要多次系统交互才能完成)
在系统要帮助收银员完成销售处理
UR1.1:系统应该允许客户经理添加、修改或者删除会员个⼈信息。(问题域) UR1.2:系统应该记录会员的购买信息。 UR1.3:系统应该允许客户经理查看会员的个⼈信息和购买信息。 UR1.4:系统应该允许客户经理查看所有会员的统计信息。
系统级需求(System Requirement)
需求分析模型:用户对系统行为的期望,每个系统级需求反映了一次外界与系统的交互行为,或者系统的一个实现细节(和用户需求有着很大的区别)
在接到客户经理的请求后,系统应该为客户经理提供所有会员的个人信息。
SR1.3.1在接到客户经理的请求后,系统应该为客户经理提供所有会员的个⼈信息。 SR1.3.2在客户经理输⼊会员的客户编号时,系统要提供该会员的个⼈信息。 SR1.3.3在客户经理选定⼀个会员并申请查看购买信息时,系统要提供该会员的历史购买记录。 SR1.3.4经理可以通过键盘输⼊客户编号,也可以通过读卡器输⼊客户编号。
3. 需求类型
1. 项⽬需求
- R5:项⽬的成本要控制在60万元⼈⺠币以下。
- R6:项⽬要在6个⽉内完成。
2. 过程需求
- R7:在开发中,开发者要提交软件需求规格说明⽂档、设计描述⽂档和测试报告。
- R8:项⽬要使⽤持续集成⽅法进⾏开发。
3. 系统需求
1. 软件需求
1. 功能需求
和系统主要共作相关的需求,即在不考虑物理约束的情况下,用户希望系统所能够执行的活动,这些活动可以帮助用户完成任务。功能需求主要表现为系统和环境之间的行为交互。
- 最常⻅、最主要和最重要的需求
- 能够为⽤户带来业务价值的系统⾏为
- 最需要按照三个抽象层次进⾏展开
- 软件产品产⽣价值的基础
Eg.在接到客户经理的请求后,系统应该为客户经理提供所有会员的个人信息。
2. 数据需求
(属于功能需求的一种,DR):功能需求的补充:如果在功能需求部分明确定义了相关的数据结构,那么就不需要再行定义数据需求。数据需求是需要在数据库、文件或者其他介质中存储的数据描述,通常包括下列内容:
各个功能使用的数据信息;
使用频率;
可访问性要求;
数据实体及其关系;
完整性约束;
数据保持要求。
Eg.系统需要存储的数据实体及其关系为图 6-14 的内容。(数据实体及其关系)
Eg.系统需要存储 1 年内的销售记录和退货记录。(数据保持)
3. 性能需求
系统整体或系统组成部分应该拥有的性能特征,例如 CPU 使用率、内存使用率等。
速度:系统完成任务的时间
(eg.所有用户查询必须在 10s 内完成)
容量:系统能存储的数据量
(eg.系统因该能够存储至少 100 万个销售信息)
吞吐量:系统在连续的时间内完成的事务数量
(eg.解释器每分钟应该能够至少解析 5000 条没有错误的语句)
负载:系统可以承载的并发工作量
(eg.系统应该允许 50 个营业服务器同时从集中服务器上进行数据的上传或下载)
实时性:严格的实时要求
(eg.系统监测到异常时,监视器必须在 0.5s 内发出警报,和故障警报不一样,故障不是系统的正常功能)
4. 质量属性
(QA):系统为了满足规定的及隐含的所有要求而需要具备的要素称为质量
往往会有形容词和副词
可靠性:在规格时间间隔内和规定条件下,系统或部件执行所要求能力的能力。
(在进行数据的下载和上传中,如果网络故障,系统不能出现故障。能不能检测网络中断,并且进行恢复)
可用性:软件系统在投入使用时可操作和可访问的程度或能实现其指定系统功能的概率。
(系统的可用性要达到 98%)
安全性:软件组织对其程序和数据进行未授权访问的能力,未授权的访问可能是有意,也可能是无意的。
(VIP 顾客只能查看自己的个人信息和购买记录)
可维护性:软件系统或部件能修改以排除故障、改进性能或其他属性或适应变更了的环境的容易程度,包括可修改性(Modifiability)和可扩展性(Extensibility)。
(如果系统要增加新的特价类型,要能够在 2 个人月内完成)
可移植性:系统或部件能从一种硬件或软件环境转换至另外一种环境的特性。
(集中服务器要能够在 1个月内从 Window 7 操作系统更换到 Solaris 10 操作系统。)
易用性:与用户使用软件所花费的努力及其对使用的评价相关的特性。
(使用系统 1 个月的收银员进行销售处理的效率要达到 10 件商品/分钟。)
5. 对外接口
系统和环境中其他系统之间需要建立的接口,包括硬件接口、软件接口、数据库接口等等。
接口的用途
接口的输入输出
数据格式
命令格式
异常处理要求
Eg.注册使用 Google Maps API
6. 约束
进行系统构造时需要遵守的约束,例如编程语言、硬件设施等
系统开发及运行的环境(包括目标机器、操作系统、网络环境、编程语言、数据库管理系统等)
Eg.系统使用 Java 语言进行开发
问题域内的相关标准(包括法律法规、行业协定、企业规章等。)
商业规则:(用户在任务执行中的一些潜在规则也会限制开发人员设计和构建系统的选择范围)
Eg. 已过保质期的食品不能销售
Eg. 顾客可以使用美元付款
2. 硬件需求
3. 其他需求
4. 其他需求
- R9:系统要购买专⽤服务器,其规格不低于….。
- R10:系统投⼊使⽤时,需要对⽤户进⾏1个星期的集中培训。#
4. 例题
1. 例1
以ATM存款功能为例
- 业务需求:提供存款功能
- 用户需求:系统允许用户存入现金并记录在对应银行卡中
- 系统级需求:在用户放入现金后,系统应该能够清点现金数额,并在清点完毕后,显示数额,请用户核对
性能需求:
- 速度:系统应该在3s内完成单个操作,查询操作响应速度不得超过1s
- 负载:系统应该允许地区内所有ATM及同时从服务器上进行运作
- 实时性:系统应该在0.5秒内同步数据
质量属性:
- 安全性:系统应该保护用户的存取款信息不被非法用户获取;
- 易用性:系统应该保证操作界面容易上手
对外接口:
- 系统与数据库接口:如果发生异常,要抛出异常并回滚
约束:用java开发
数据需求:系统需要存储用户3年以内的详细存取款记录信息
2. 例2
功能需求,与系统主要功能相关
数据需求,规定了数据描述和数据的输入格式(PS.但我个人觉得是对外接口)
3. 例3
该功能涉及2个用例
- 用例1:手工创建询价单
- 参与者:采购人员
- 主要流程:
- 采购人员登入系统,输入供应商、产品等信息
- 系统记录供应商、产品、库存等信息
- 采购人员结束创建过程
- 系统生成并展示采购询价单
- 用例2:自动生成询价单
- 参与者:库管员
- 前置条件:仓库经理已设置产品的再订货规则
- 主要流程:
- 库管员登录系统
- 系统确认权限
- 库管员点击运行排程
- 系统按照再订货规则和销售订单及库存情况自动生成采购询价单,并显示
第六章 需求分析方法
1. 用例图
四要素:用例、参与者、关系、系统边界
2. 分析类图(概念类图)
根据用例的文本描述,识别候选类
- 名词分析、行为分析
筛选候选类,确定概念类
- 根据系统需求
- 是否有状态+行为
- 只有行为:
- 只有状态:其他概念类的属性
识别关联
识别重要属性
3. 系统顺序图
4. 状态图
- 状态:一组可观察的情况,描述了一个系统在给定时间的行为
- 状态转换:从一个状态到另一个状态的转换
- 事件:使系统表现出某种可预测的行为形式的事件
- 行为:由于过渡而发生的过程
5. 例题
1. 例1
画用例图
2. 例2
第七章 需求文档化和验证
1.为什么需要需求规格文档?结合实验说明
- 方便交流:软件开发过程中,子任务与人员之间存在错综复杂的关系,存在大量的沟通和交流,所以要编写软件开发中要编写不同类型的文档,每种文档都是针对项目中需要广泛交流的内容。因为软件需求需要进行广泛交流,所以要把需求文档化。
- 跟踪和度量:需求规格说明是在软件产品的角度以系统级需求列表的方式描述软件系统解决方案,书写需求规格说明,可以建立管理控制的基线,方便任务分配,制定工作计划,进行跟踪和度量。
- 过程管理:在实验中,需求规格的重要性不只体现在结果上,还包括中间过程,在书写需求规格过程中,才真正把问题域的问题和分析模型的成果转化为系统级需求,方便小组成员真正明确需求,个人认为在这个阶段包含一部分的需求在发现和完整化。
2. 需求示例修正
1. 用例选择错误
- 用例粒度
- 不要将用例细化为单个操作,如将用户管理细化为增加、修改和删除,需要联合才能体现业务价值
- 不要将同一个业务目标细化为不同用例,比如特价策略制定和赠送策略制定,合并为销售策略制定
- 将明显不同的业务事件分开,如会员管理用例应该细化为发展会员和礼品赠送
- 用例价值
- 登录、数据验证、连接数据库没有价值,不作为用例
- 是否和系统产生交互
- 顾客不是参与者,不与系统产生交互
2. 技术文档撰写错误
- 技术文档写作要点(简洁,精确,易读,易修改)
- 简洁:动词名词+辅助词,不要使用复杂长句、形容词和副词。
- 精确:避免歧义。
- 易读(查询):有效使用引言、目录、索引等能够增强文档易读性的方法,使用系统化的方式组织内容信息,提供文档内容的可读性。
- 易修改:使用相同的语句格式组织相关联或相似的信息;使用列表组织独立、并列的信息;使用编号表达繁杂信息之间的关系。引用而不是重复
- 需求书写要点(使用用户术语,可验证,可行性)
- 需求规格说明文档书写要点(充分利用标准的文档模板,保持所以内容位置得当;保持文档内的需求集具有完备性和一致性;为需求划分优先级)
3. 设计功能测试用例
- 以需求为线索,开发测试⽤例套件;
- 使⽤测试技术确定输⼊/输出数据,开发测试⽤例。
- 我们可以开发出黑盒测试用例
- 基于⽤例描述,可以为销售处理确定测试⽤例套件
- 测试用例套件是测试用例的集合,将有关测试用例集合在一起
第八章 软件设计基础
考个思想而已,看看就行
1. 名词解释:软件设计
- 软件设计是指关于软件对象的设计,是一种设计活动。软件设计既指软件对象实现的规格说明,又指这个规格说明产生的过程。
- 软件设计活动以需求开发的制品(需求规格说明和分析模型)为基础,构建软件设计方案描述和原型,为后期的构造活动提供规划或蓝图。
- 软件设计兼具工程性和艺术性,由于软件系统的可变性,软件设计具有演化性,也因为软件设计的过程实际上就是一系列决策发生的过程,软件设计具有决策性。
2. 软件工程的核心思想
抽象:横向上将系统分解为几个相对简单的子系统以及各子系统之间的关系
分解:纵向上聚焦各子系统的接口(区别于实现,各子系统之间交互的契约),可以分离接口和实现,使得人们更好地关注软件系统本质,降低复杂度
3. 软件工程三个层次
高层设计:基于反映软件高层抽象的构建层次,描述系统的高层结构、关注点和设计决策
中层设计:更加关注组成构件的模块的划分、导入/导出、过程之间的调用关系或者类之间的协作
低层设计:深入模块和类的内部,关注具体的数据结构、算法、类型、语句和控制结构等体系结构三个层次
第九、十章 体系结构
1. 体系结构风格的优缺点
1
#### 1. 主程序子程序
优点:
- 流程清晰,易于理解
- 强控制性
缺点:
- 程序调用是一种强耦合的连接方式,非常依赖交互方的接口规格,这会使得系统难以修改和复用
- 程序调用的连接方式限制了各部件之间的数据交互,可能会使得不同部件使用隐含的共享数据交流,产生不必要的公共耦合,进而破坏它的“正确性”控制能力
2. 面向对象
优点:
- 内部实现的可修改性(隐藏内部实现)。
- 易开发、易理解、易复用的结构组织(契合模块化思想)。
缺点:
- 接口的耦合性(由于方法调用机制,接口的耦合性无法消除)
- 标识(Identity)的耦合性(一个对象要和其他对象交互,必须知道标识)
- 副作用:难以理解、高耦合性以及数据的不一致视图
3. 分层
优点:
- 设计机制清晰,易于理解(抽象层次分离,隔离复杂度)。
- 支持并行开发(层次之间遵守程序稳定的接口)。
- 更好的可复用性与内部可修改性(接口的稳定性,不同层次的部件能够互相替代)。
缺点:
- 交互协议难以修改(可能需要改变所有的层次,接口具有强耦合性)。
- 性能损失(禁止跨层调用)。
- 难以确定层次数量和粒度。
应用:
- ISO网络通信模型
- TCP/IP网络通信模型
4. MVC
Model-View-Controller
- 组件
- 模型组件负责保持问题域知识和确认视图层的修改
- 视图组件负责显示信息给用户并且将用户的行为传递给控制器
- 控制器
- 修改模型的状态:将用户的行为和模型的更新映射起来
- 选择用来反映的视图
- 连接件:方法调用,信息,事件
优点:
易开发性(分别抽象了业务逻辑,表现和控制机制清晰,易于开发)
视图和控制的可修改性。
适宜于网络系统开发的特征。
(MVC 不仅允许视图和控制的可修改性,⽽且其对业务逻辑、表现和控制的分离使得⼀个模型可以同时建⽴并保持多个视图,这⾮常适⽤于⽹络系统开发)。
缺点:
复杂性。
MVC将⽤户任务分解成了表现、控制和模型三个部分,这增加系统的复杂性,不利于理解任务实现。
模型修改困难。
视图和控制都要依赖于模型,因此,模型难以修改。(往往会我们带来比较高的复杂度问题)
2. 包的原则
1. 内聚性
1. Common Closure Principle (CCP) 共同封闭原则
- 包中所有类对于同一类性质的变化应该是共同封闭的,一个变化若对一个包产生影响,则对该包中的所有类产生影响,而对于其他包不造成任何影响。
- 包尽可能大,和CRP互斥
2. Common Reuse Principle (CRP) 共同重用原则
- 一起被重用的应该在一起
- 遵循CRP通常会导致软件包拆分:获得更多,更小,更专注的包
3. Reuse-Release Equivalency Principle (REP) 重用发布等价原则
重用的粒度就是发布的粒度
相关联的包一起发布,几个协作类组成一个包
2. 耦合性
1. The Acyclic Dependencies Principle (ADP) 无环依赖原则
在包的依赖关系图中不能存在环。必须是有向无环图。
修改方式:
- DIP,依赖接口,实现接口
- 分离包
2. Stable Dependencies Principle (SDP) 稳定依赖原则
朝着稳定(别人的修改不影响我)的方向进行依赖
3. Stable Abstractions Principle (SAP) 稳定抽象原则
- 稳定的包应该是抽象的包(接口)
- 不稳定的包应该是具体的包
3. 体系结构开发集成测试用例
桩(stub)模仿的是下层模块,用来测试上层;
而驱动(driver)则模仿的是上层模块,用来测试下层。
所以,驱动需要利用下层提供的接口,来实现其模仿的模块的功能
1. 大爆炸集成
- 大爆炸集成:将所有模块一次性组合在一起。
- 优点:可以在短时间内迅速完成集成
- 缺点:一次运行成功可能性不高,不容易发现bug
2. 自顶向下集成
- 自顶向下集成是对分层次的架构,先集成和测试上层的测模块,下层的模块用伪装的具体接口的桩程序。
- 自顶向下集成的优点:
- 按深度优先可以⾸先实现和验证⼀个完整的功能需求;
- 只需顶端⼀个驱动(Driver);
- 利于故障定位。
- 自顶向下集成的缺点:
- 桩的开发量大;
- 底层验证被推迟,且底层组件测试不充分。
- 但是一般会带来比较好的顶层设计的优势。
- 自顶向下基层适用于控制结构比较清晰和稳定、高层接口变化较小、底层接口未定义或经常被修改、控制组件有具有较大的技术风险的软件系统。
- 测试M1的时候,我们使用假的M2、M3、M4来进行代替(简单的代替这个模块)(被叫做Stub)
3. 自底向上集成
- 高层设计的错误不会被很快的发现
- 而这往往被我们认为会带来比较致命的问题
- 优点:
- 对底层组件较早进行验证
- 底层组件开发可以并行
- 桩的工作量少
- 缺点:
- 驱动的开发作用量大
- 对高层的设计被推迟,设计上的高层错误并不能被及时发现
4. 持续集成
- 尽早集成
- 频繁集成
持续集成需要用到版本控制工具和持续集成工具
4. 包图
1. 逻辑视图
2. 物理视图
5. 进程图
6. 接口
7. 例题
1. 例1
2. 例2
第十一章 人机交互设计
1. 名词解释:可用性
易⽤性不仅关注⼈使⽤系统的过程,同时还关注系统对使⽤它的⼈所产⽣的作⽤。它不是单维度的质量属性,⽽是多维度的质量属性。
可认为易⽤性包含五个不同的维度,包括易学性、易记性、效率、出错率和主观满意度。
度量⽅式:
- 易学性:新手用户容易学习,能够很快使用系统。
- 效率:熟练的用户可以高效使用它
- 易记性:使用过软件系统的用户,能够有效记忆或快速重新学会使用该系统。(超市可以缓存之前的信息)
- 出错率:几乎没有错误,可以从错误中快速恢复
- 主观满意度:让用户有良好的体验。
2. 界面设计的注意事项
简洁设计:
- 7+-2原则
- 不在一个窗口展示过多信息,功能清晰明确
- 摘要图片优于文字描述
- 不要大菜单,不要过多的信息类别,不要太多的颜色和字体
一致性设计:
- 依据精神模型,让系统中相似的任务有一致的交互机制(按钮位置等等)
低出错率设计:
避免犯错
数值域不可输入字符
友好建议:
提供简洁的指导帮助⽤户消除错误,用户输入错误信息,系统会标注出来,而不是让用户重写整段代码
语言清晰,表达准确,建设性帮助,友好,不应责备
易记性
- 减少用户的记忆负担
- 使用逐层递进的范式展示信息
- 使用直观的快捷方式
- 设置有意义的默认值
所见即所得
3. 精神模型和差异性
精神模型:就是用户进行人机交互时头脑中的任务模型。人机交互设计需要依据精神模型进行隐喻设计,依据隐喻将控件功能与已知的熟悉事物联系起来,实现界面视觉提示和系统功能之间的知觉联系
差异性:对不同用户群体的任务模型是有差异的,所以对他们的人机交互设计也要有差异。按照用户群体自身的特点,可以将其划分为新手用户、专家用户和熟练用户
4. 导航、反馈、协作式设计
使用导航
导航的目的就是为用户提供一个很好的完成任务的入口,好的导航会让这个入口非常符合人的精神模型
全局导航控件包括窗口、菜单、列表、快捷方式、热键等等。
局部导航通过安排布局细节,制造视觉上的线索来提供导航。
反馈
按钮点击等在视觉(声音)上给用户反馈,让用户意识到行为的结果
反馈的目的是提示用户交互行为的结果,但不能打断用户工作时的意识流。对用户思考和反应时间的把握。
协作式设计
人和计算机是人机交互的两方,其中人的因素是比较固定的,一定时期内不会发生大的变化,所以要让两者交互顺畅,就需要让计算机更多地适应人的因素,这也是人机交互设计以用户为中心的根本原因。这种调整计算机因素以更好地适应并帮助用户的设计方式被称作为协作式设计。
5. 例题
1. 例1
对左图:
- 违反了简洁设计,交互信息过多,摘要图片比描述文字更清晰
- 违反了一致性原则,按钮位置不一致,如cancel和ok的位置,不符合精神模型(已存在相似系统)
- 违反了低出错率原则,选择的进度条不明显
- 违反了易记性原则,没有清晰的导航或直观的快捷方式,没有减少记忆负担,将所有certificate列出,用户不容易记住
2. 例2
- 符合简洁设计原则,模块结构清晰,没有提供过多的信息,符合7+2的原则,颜色简单
- 符合一致性原则,符合用户的精神模型,与已有类似的界面相似
- 符合易用性原则,递进式地展示菜单,使用直观的快捷方式,减轻用户的记忆负担
- 所见即所得
第十二章 详细设计
1. 职责分配
1. GRASP原则
General Responsibility Assignment Software Patterns
- 特点:
- 低耦合:分配一个职责要保证低耦合度
- 高聚合:分配一个职责的时候要保持类的高聚合度
- 信息专家:将一个职责分配给专家 - 拥有履行职责所必须的信息的类
- 创建者:创建规则在后面
- 控制者:控制规则在后面(避免大多数信息由一个类发出、组件相对较小、行为职责和数据绑定、职责单一)
- 拇指原则:当有替代设计选择时,请仔细研究替代方案的内聚和耦合影响,以及未来可能对替代方案的演变压力。选择具有良好内聚性、耦合性和稳定性的替代方案。
- 信息专家:统一提供对外的接口,而不是某一个具体的接口,数据和行为不要分开
- 创建规则:如果有以下情况,则由创建者分配 B 类创建 A 类实例的职责:
- B 聚合了 A 对象
- B 包含了 A 对象
- B 记录了 A 的实例
- B 要经常使用 A 对象
- 当 A 的实例被创建,B 具有传递给 A 的初始化数据(也就是 B 是创建 A 的实例这项任务的信息专家)
- 在有选择的地方,更喜欢 B 聚合或包含 A 对象
2. 协作
- 从小到大,将对象的小职责聚合形成大职责;
- 从大到小,将大职责分配给各个小对象。
- 这两种方法,⼀般是同时运⽤的,共同来完成对协作的抽象。
- 顺序图
- 可以⽤顺序图表示对象之间的协作。顺序图是交互图的⼀种,它表达了对象之间如何通 过消息的传递来完成⽐较⼤的职责。
- 包含两部分:对象本身和对象之间的信息流
3. 控制风格
协作中的概念
- 集中式控制风格:做决策的只有一个对象
- 委托式控制风格:做出决策的对象不只有一个,职责的分解决定了控制对象的层次。
- 分散式控制风格:无明确的控制对象,每个对象只承担想对较小的职责,完全靠各个对象自治的方式来实现大的职责
4. 设计类图
5. 详细顺序图
6. 写作的测试
- Mock Object:类间协作的桩程序
- 与体系结构集成的stub类型桩程序不同,Mock Object要求自身的测试代码更简单,不用测试就能保证正确性
Mock对象主要用于验证某些方法的调用。它们不仅可以模拟对象的行为,还可以记录并验证对象的交互。
特点:
- 行为验证:Mock对象关注的是对象间的交互和行为。可以验证某个方法是否被调用、调用了多少次、用什么参数调用等。
- 灵活性高:Mock对象通常是动态创建的,可以根据测试需求调整其行为。
- 用于复杂交互测试:特别适用于测试对象间的复杂交互和依赖关系。
Stub对象主要用于提供方法的固定返回值,不关心方法是否被调用以及如何被调用。它们通常用于模拟返回特定数据的对象,以便于测试中的某些情境。
特点:
- 状态验证:Stub对象关注的是方法的返回值或状态,而不是交互。
- 简单实现:Stub对象通常是静态的,主要用于返回预定义的值。
- 用于状态测试:特别适用于测试某个对象的状态或单个方法的输出,而无需关注其他对象的交互。
第十三章 模块化与信息隐藏
1. 名词解释:耦合与内聚
- 耦合
- 耦合描述的是两个模块之间关系的复杂程度。
- 模块耦合性越⾼,模块的划分越差,越不利于软件的变更和复⽤。
- 内聚
- 内聚表达的是⼀个模块内部的联系的紧密性。
- 内聚性越⾼越好,越低越不易实现变更和复⽤。
2. 耦合
耦合:内容、公共、重复不可接受,控制、印记可以接受,数据最理想
1. 内容耦合
一个模块直接修改另一个模块的内容(成员变量、函数等)
2. 公共耦合
模块之间共享全局数据结构
3. 重复耦合
一个模块有逻辑上相同的重复代码
4. 控制耦合
一个模块给另一个模块传递了控制信息(除了数据还有控制信号,并且违反了单一职责原则)
5. 印记耦合
两个模块共享一个数据结构,但是只用了其中一个部分(发送多了)
6. 数据耦合
两个模块的所有参数是同类型的数据项(发送正好)
3. 内聚
内聚:偶然和逻辑不可接受,时间、过程、通信可以接受且不可避免,功能和信息最理想
1. 偶然内聚
完全不相关
2. 逻辑内聚
执行一系列操作,具体操作交给具体模块(如 swtich),解决控制耦合的方法
3. 时间内聚
执行一系列和时间有关的操作,比如构造方法和析构方法
4. 通信内聚
执行一系列与步骤顺序有关的操作,并且这些操作是在相同的数据结构上。
5. 功能内聚
模块只执行一个操作或达到一个单一目的
6. 信息内聚
模块进行许多操作,各自有各自的入口,相互独立,且在相同的数据结构上完成操作。
4. 信息隐藏
每个模块都隐藏了重要设计决策的实现,因此只有该模块的组成部分才知道详细信息:特别是如果存在所有可能的设计更改的列表,则隐藏假设列表
1. 两种常见的信息隐藏决策
- 按职责分解-根据需求分配的职责,因为实践表明,需求是经常变化的,频率和幅度都很大;
- 按算法分解-内部实现机制,常见的变化主题包括硬件依赖,输入输出形式,非标准语言特征和库,负责的设计和实现,复杂的数据结构,复杂的逻辑,全局变量。数据大小限制等。
2. 信息隐藏程度的好坏
- 封装数据和行为
- 封装内部结构
- 封装对象的引用
- 委托隐藏了与其他对象的协作
- 封装类型信息
- 封装可能存在的变更
3. 例题
1. 例1
View负责了展示,Logic负责了统计求和。Data负责各个数据的存储。
第十四/十五章 面向对象的模块化
1. 访问耦合
2. 设计规则/模块化原则
1. 降低隐式耦合
1. 全局变量是有害的
2. 简洁
3. 不要有代码重复
2. 降低访问耦合
1. 面对接口编程
编程到所需的接口,不仅是受支持的接口
按照约定设计
模块/类合同:所需方法/提供的方法
方法合同:前提条件,后置条件,不变式
2. 接口分离原则(ISP)/也叫接口最小化原则
3. 迪米特法则
- 通俗说法
- 你可以自己玩。(this)
- 你可以玩自己的玩具,但不能拆开它们(自己的成员变量)
- 你可以玩送给你的玩具。(方法)
- 你可以玩自己制作的玩具。(自己创建的对象)
- 更加形式化的说法:
- 每个单元对于其他单元只能拥有优先的知识,只是与当前单元紧密联系的单元
- 每个单元只能和它的朋友交谈,不能和陌生单元交谈
- 只和自己的直接的朋友交谈
3. 降低继承耦合
1. LSP里氏替换原则
子类型必须能够替换掉基类型而起同样的作用。
保持父类的方法接口不变;保持父类方法的实现语义不变;(不能用vector实现stack)
只要调用一个接口,不论哪种子类或者父类本身,都可以完成相同语义的工作
解决方案:在父类中添加方法或者函数,或者拆分接口
2. 组合代替继承
- 组合优于继承
- 使用继承实现多态
- 使用委托不继承重用代码!
4. 提高继承内聚
1. 集中信息和行为
2. 单一职责原则
- 班级只有一个改变的理由:职能/职责的凝聚力
- 几个职责:表示更改的几个原因→更频繁的更改
5. 其他
1. 封装——分离接口与实现
含义:
- 将数据和行为同时包含在类中
- 分离对外接口与内部实现
实现细节:
- 封装数据和行为(不要每个私有数据都有getter和setter,也不要暴露存储数据和推导数据calculateAge)
- 封装内部结构(public Position getPosition 代替 public Position[] getPositions)
- 封装其他对象的引用(新对象的引用返回)
- 封装类型信息(隐藏子类,只知道共性类别)
- 封装潜在变更
2. OCP开闭原则
对扩展开放,对修改关闭,添加新的代码而不需要修改原来的代码就能实现变更
只要是发生了需求变更需要修改原有代码,则违反此原则
3. DIP依赖倒置
高级模块不应该依赖于低级模块,两者都应该依赖于抽象
为具体类建立抽象接口并分离该接口是中实现DIP的基本手段
3. 例题
1. 例1
第一个不合理,栈不能继承向量,向量很多方法栈用不到
第二个合理,雇员继承人
第十六章 设计模式
1. 如何实现可修改性、可扩展性、灵活性
- 实现的可修改性:涉及到大的场景的修改
- 对已有实现的修改
- 例如:修改现有促销策略
- 实现的可扩展性(DIP & OCP)
- 对新的实现的扩展
- 例如:增加一条新的促销策略(策略模式)
- 实现的灵活性
- 对实现的动态配置
- 例如:动态修改更改某商品对应促销策略
将接口和实现分离的实现方法:
- 通过接口和实现该接口的类完成接口与实现的分离
- 通过子类继承父类,将父类的接口和子类的实现分离
2. 设计模式
1. 策略模式
p266
2. 抽象工厂模式
抽象工厂模式:定义了一个创建对象的接 口,由子类决定要使实例化哪一个类。工 厂方法让类的实例化延迟到子类。
3. 单件模式
每次想得到这个类 的一个对象的引用的时候,都指向唯一的那 个对象。无论我创建多少次这个类的对象, 其实总共还是只创建了一个对象。
4. 迭代器模式
往往可能只是希望挨个访问某个聚合结构。而且我们往往并不希望让函数知道到底是什么样 的聚合结构,是LinkedList还是HashSet,是Collection 还是Map。这个时候,迭代器模式就可以帮我们。
第十七、十八章 软件构造、代码设计
1. 构造包含的活动
详细设计、编程、测试、调试、代码评审、集成与构建、构造管理
2. 名词解释:重构、测试驱动开发、结对编程
- 重构
- 修改软件系统的严谨⽅法,它在不改变代码外部表现的情况下改进其内部结构。
- 不改变代码的外部表现,是指不改变软件系统的功能。
- 改进代码的内部结构是指提升详细设计结构的质量,使其能够继续演化下去。
- 测试驱动开发
- ⼜称为 测试有线(test first)的开发,它随着极限编程⽅法的普遍应⽤⽽得到发展和普及。 测试驱动开发要求程序员在编写⼀段代码之前,优先完成该段代码的测试代码。
- 完成测试代码后,程 序员再编写程序代码,并在编程中重复执⾏测试代码,以验证程序代码的正确性。
- 结对编程
- 两个程序员挨着坐在⼀起,共同协作进⾏软件构造活动。
- 两个程序员可以经常互换⻆⾊。
3. 改善代码
易维护性:
- 缩进表达逻辑结构
- 将相关逻辑组织在一起
- 用空行分割逻辑
- 语句分行
- 命名要规范要有意义
- 要有注释
- 不要硬编码
- 减少重复代码
可靠的代码:
- 小型任务分解
- 复杂决策的转化
- 使用新的布尔变量简化复杂决策
- 使用有意义的名词简化复杂决策 (抽象成判断的函数)
- 表驱动
- 数据使用
- 变量与命名相符、单变量单目的、限制全局变量、不要用突兀的数字
- 明确依赖关系(可以写到注释里面 @see)
4. 契约式编程
如果一个函数或方法,在前置条件满足的情况下开始执行,完成后能够满足后置条件。
异常和断言
5. 防御式编程
6. 表驱动
- 数据的保存一定要能够节省计算(核心思想),用空间换取时间
- eg:包括所得税中的速算
- 声明多个一维数组,存储系列同类型的边界条件
- 然后通过for循环,统一用一个下标i访问所有数组的值
7. 例题
例1
###
代码缺点:
- 直接通过字符串来返回结果,硬编码不利于修改,复用。
- 即使使用字符串是合理,也应该在ifelse中设置output的值。再统一调用 writer.print(output)。
第十九章 软件测试
1. 黑盒测试
黑盒测试是将测试对象作为一个黑盒子,完全基于输入和输出数据来判断测试对象的正确性。
等价类划分
- 把所有可能的输入数据,即程序的输入域划分为若干部分(子集),从每个子集中选取少量具有代表性的数据作为测试用例。
- 例子
边界值分析
决策表
- 决策表是为复杂逻辑判断设计测试用例的技术。决策表示由条件声明、行动声明、规则选项和行动选项等四个象限组成的表格。
状态转换
根据状态转换图,建立测试对象的转换表,状态转换的每一类都应该被设计为测试用例
- 输入:方法+当前状态
- 输出
2. 白盒测试
白盒测试是将测试对象看做透明的,不关心测试对象的规格,而是按照测试对象内部的程序结构来设计测试用例进行测试工作。
1. 语句覆盖
确保测试用例的每一行代码都被覆盖到
2. 条件覆盖
每个判断的每个结果都被至少满足一次
3. 路径覆盖
确保程序每条独立的路径都被执行一次
房春荣领域
1. 软件生命周期模型
2. 软件过程模型
1 . 瀑布模型
瀑布模型是按照软件生命周期模型将软件开发活动组织为需求开发、软件设计、软件实现、软件测试、软件交付和软件维护等活动,并且规定了它们自上而下、相互邻接的次序。
优点:为软件开发活动定义了清晰的阶段划分(包括输入/输出、主要工作及其关注点),这让开发者能够以关注点分离的方式更好地进行那些复杂度超越个人能力的软件项目的开发活动。
缺点:
- 对文档的过高的期望具有局限性
- 对开发活动的线性顺序假设具有局限性
- 客户、用户的参与具有局限性:成功的项目开发需要客户、用户从始至终的参与,而不仅仅是一个阶段。
- 里程碑粒度具有局限性:里程碑粒度过粗,基本丧失了“早发现缺陷早修复”这一思想
适用于比较成熟,没有技术难点的软件
2. 增量迭代模型
增量迭代模型是在项目开始时,通过系统需求开发和核心体系结构设计活动完成项目对前景和范围的界定,然后再将后续开发活动组织为多个迭代、并行的瀑布式开发模型。
少量的不确定性和影响不大的需求变更通过迭代的方式加以解决。
优点:
- 迭代式开发更加符合软件开发的实践情况,具有更好的适用性;
- 并行开发可以帮助缩短软件产品的开发时间;
- 渐进交付可以加强用户反馈,降低开发风险。
缺点:
- 由于各个构件是逐渐并入已有的软件体系结构中的,所以加入构件必须不破坏已构造好的系统部分,这需要软件具备开放式的体系结构。
- 增量交付模型需要一个完备、清晰的项目前景和范围以进行并发开发规划,但是在一些不稳定的领域,不确定性太多或者需求变化非常频繁,很难在项目开始就确定前景和范围。
适用范围:适用于大规模软件系统的开发。
3. 演化模型
演化模型将软件开发活动组织为多个迭代、并行的瀑布式开发活动。演化模型能够更好地应对需求变更,更适用于需求变更比较频繁或不确定性较多的领域。
优点:
- 使用了迭代式开发,具有更好的适用性,尤其是其演化式迭代安排能够适用于那些需求变更比较频繁或不确定性较多的软件系统的开发;
- 并行开发可以帮助缩短软件产品的开发时间;
- 渐进交付可以加强用户反馈,降低开发风险。
缺点:
- 无法在项目早期阶段建立项目范围,所以项目的整体计划、进度调度、尤其是商务协商事宜无法准确把握;
- 后续迭代的开发活动是在前导迭代基础上进行修改和扩展的,这容易让后续迭代忽略设计分析与设计工作,蜕变为构建-修复方式。
适用与不稳定领域的大规模软件系统开发