第一章
软件的三个根本特性(三个方面的特征)
- 能够在通用计算机硬件之上运行
- 能够灵活面向不同的应用目标实现相应的解决方案
- 内容上包括程序及其文档以及相关的数据
软件发展历史
- 1940-1960年:软硬件一体化,局限于国防军工及科学计算等领域,语法发展使得编程效率逐渐提高
- 1960-2000年:软硬件分离,软件产品主要以软盘和光盘等物理介质作为分发和销售的载体,拥有网络通信能力,网络化软件逐渐成为主流。出现了众多软件企业
- 2000-2020年:基于互联网的应用软件和服务不断涌现并蓬勃发展,同时也产生了新的基于在线服务的软件分发方式(应用商城)和商业模式。越来越多的应用提供了移动客户端访问方式。
- 2020年至今:软件成为信息化社会基础设施,重塑了生活的方方面面。
软件的分类
- 按照软件应用领域:(1)通用软件产品;(2)定制化软件产品
- 按照软件的步数和运行形态:(1)信息系统;(2)嵌入式系统;
软件及相关技术的发展改变了哪些行业和领域?
可以从医疗、教育、交通、金融、娱乐等角度入手
软件开发的一般过程
- 问题抽象
- 问题理解
- 编写程序
- 部署运行
软件开发是一个从问题空间到解空间的知识转换过程
软件工程的理解
软件开发的工程化或工程化的软件开发
编程与工程化软件开发的区别
- 所编写的程序没有针对来自现实世界的需求
- 不考虑相关的质量要求
- 没有按照工程化的过程进行开发
- 不考虑长期演化和维护的问题
软件工程的目标
质量、成本、时间
软件工程也具有工程的基本内涵和特点:
- 过程标准化
- 理论和实践支撑
- 质量有保障
- 实用性原则
软件工程的根本特性
- 可靠性
- 运行效率
- 经济性
- 工程
软件工程的内容层次(自上而下)
- 工具
- 方法
- 过程(流程)
- 质量关注点
![Pasted image 20250101193823.png]]
软件工程的根本性困难
- 不可⻅的逻辑产品(对⽐:物理学和化学对于制造业、建筑业等成熟领域的⼯程技术⽀撑)
- 问题空间和解空间之间的巨⼤鸿沟
- ⾯临的领域纷繁复杂、分布⼲泛,不同软件系统之间的差异性很⼤
- 软件系统的复杂度越来越⾼(远⾼于计算机硬件)
软件工程的系统观和演化观
从空间和时间两个方面将软件及其开发过程置于一个更大的社会、经济和技术环境之中,并从发展和变化的角度去理解
空间维度:系统观 (系统结构整体理解,有价值的是完整系统而非软件)
- 软件系统的计算环境及技术栈:一整套的软硬件基础提供支撑
- 软件系统的物理和社会环境:考虑环境中的社会和物理要素理解用户需求和软件角色
时间维度:演化观(持续发展全面理解,以发展眼光考虑)
- 软件系统的持续演化:指的是产品的更新
- 软件系统的迭代和演化式开发:指的是开发过程中的持续性交付和修改
软件工程师的社会责任
- 国家需求与社会需要
- 职业道德与工匠精神
- 可靠可信与可控自主
- 伦理道德与社会影响
软件工程师的职业道德
- 符合法律规定
- 满足道德规范和职业精神
- 要有责任感
根据自己的经历举例说明你写过的程序存在哪些依赖关系?这些依赖如何影响程序的正常运行?
自己的思考
软件工程师哪些方面的行为可能涉及职业道德问题(举例说明)?
自己的思考
第二章
软件过程的定义
软件过程定义了软件组织和人员在软件产品的定义、开发和维护等阶段所实施的一系列活动(Activity)和任务(Task)
软件过程的三层含义
- 个体含义:软件产品或系统在生存周期中的某一类活动的集合,如系统分析过程、实现过程
- 整体含义:软件产品或系统在所有上述含义下的软件过程的总体
- 工程含义:应用软件工程原则、方法来构造软件过程模型,并应用到软件产品的生产中,以此来提升软件生产率,降低生产成本
为什么人们相信规范化的过程(例如符合国际标准)能够保证产品(例如饮料)的质量?
科学严谨的制定依据、统一的衡量尺度与可对比性、严格的质量管控环节体现、提升品牌信誉与市场竞争力、监管与违规惩处机制保障。
软件过程模型
软件过程模型是对开发人员所采用的软件开发方法与过程组织整体结构的抽象描述要达了软件过程的结构框架。
瀑布模型
核心思想是将软件开发的各个过程以线性的、顺序的方式进行:
- 首先,清晰地了解要解决问题的需求
- 然后顺序地开展策划、建模、构建和部署等工作
- 最终交付完整的软件产品,并开展后续的技术支持和维护
反应了一种软件开发过程理想: - 每个阶段的具体活动内容和目标都清晰定义
- 阶段性的产出都能被明确签核(sign-off)
- 前一个阶段完成后才会进入下一个阶段
相对于早期软件过程定义不清晰、缺乏工程化的开发方法而言是一大进步
主要问题:
- 实际项目很少完全遵循瀑布模型提出的顺序
- 客户难以在一开始就完整、准确地描述需求
- 可执行的软件产品交付太晚,造成巨大的风险
增量模型
增量模型的思想是将软件产品的开发分成若干增量,每个增量执行一系列活动并且产出一个可执行的中间产品,直到族中完成完整的软件目标。
每次增量开发选择一部分需要,这通常是将当前最关键、最核心的需求作为交付的目标。
强调每个增量提交一个可运行的软件产品,用于发现目标和新需求。
本质上是以迭代的方式使用瀑布模型。
演化模型
螺旋模型:通过周期性的迭代将各个阶段以螺旋扩增的方式进行编排。
主要问题:难以判断螺旋演进何时结束
螺旋模型:风险驱动的周期性迭代
一个重要形式:原型开发范式
强调开发软件原型
用户需求通常是模糊的、不完整的甚至相互之间存在矛盾。因此,借助原型可以更好理解彼此对于软件系统的期望。
根据使用目的不同,分为:
- 抛弃式原型:对某些特定问题的探索和实验,。具有明确的目的性,不宜集成到正式产品中。在完成原型、达到目的后,应当被抛弃。
- 增量式原型:目标系统的一个可运行的子集,关键设计决策应该在增量构建过程中逐步得到确定。确保后续的增量都建立在一个合适的基础上。
原型开发是客户与开发团队之间沟通的重要技术手段
统一过程模型
作为一种过程模型和方法框架,一定程度上总结了传统软件过程中好的特征和性质。
增量、迭代的过程流,每个迭代涉及核心过程工作流和核心支持工作流中的多个过程
不同阶段迭代工作流中的过程工作量是不同的
特点
- 建立了增量、迭代的过程流:将产出一次软件增量的过程作为一个循环,每个循环有初始、细化、构造、移交四个阶段构成。
- 强调与看客户沟通以及从用户角度描述系统并保持该描述一致的重要性:采用用例作为描述系统需求的手段。用例驱动是统一过程的重要特点。采用统一建模语言UML进行描述。
- 强调了软件体系结构的重要性:以软件体系结构为中心。软件体系结构是系统整体设计的高度抽象。
增量迭代、用例驱动、以体系结构为中心
在本学期的课程项目中,你们组的开发过程大致将以什么样的方式组织?
自己思考
能力成熟度模型集成(CMMI)
五个成熟度等级:初始级、已管理级、已定义级、量化管理级、优化级
计划驱动和敏捷开发的区别以及各自的优缺点
计划驱动:所有过程活动均事先计划,按照计划衡量进度
- 需求可以事先清楚、完整定义,且不会有太大变化
- 最终得到的软件系统有较高的可靠性、安全性要求
- 涉及多个部门或团队,涉及复杂的协调和沟通
敏捷开发:只做增量的短期计划并根据变化和反馈不断进行调整
- 需求不确定且经常变化(变化蕴涵着竞争优势)
- 对于最终软件系统的可靠性和安全性要求没那么高
- 开发团队规模较小且能够充分沟通
两者常结合使用
敏捷开发的价值观
- 个体和交互 重于 过程和工具 :对于个人的要求提高,尊重个人创造性工作
- 可运行的软件 重于 详尽的文档:不否认文档重要性,但是将其视作一种沟通渠道
- 客户合作 重于 合同谈判:保证了软件开发的正确性,不易产生歧义
- 响应变化 重于 遵循计划:将变化视为正常的现象
什么样的项目适合于采用计划驱动的开发方法?什么样的项目适合于采用敏捷开发方法?(下面是AI回答,可以参考上面的区别)
计划驱动
需求明确稳定的项目
受严格法规监管的项目
大型复杂且有明确交付期限的项目
对成本预算精准把控的项目
敏捷开发
需求不确定且变化频繁的项目
需要快速响应市场变化的项目
创新性较强的项目
小型团队协作且沟通高效的项目
敏捷过程的特点:强调适应而非预测
- 客户需求(场景、故事)驱动
- 认识到有效的计划都是短期的
- 迭代地开发软件同时强调构造活动(设计与实现交织)
- 频繁交付可运行的“软件增量”
- 根据变化进行适应性调整
精益思想
核心思想:在于对系统和开发过程的“持续改善”以及“尊重人”
直观理解:消除浪费,做有价值的工作
精益思想给出五条改进系统和过程的原则
- 识别价值
- 定义价值流
- 保持价值流的流动
- 拉动系统
- 持续改善
敏捷实践方法论(了解)
Scrum
价值观:承诺、聚集、开放、尊重、勇气
主要特征:
- 基于时间盒的迭代
- 增量以及演进式开发
极限编程(XP)
价值观:沟通、简单、反馈、勇气、尊重
原则:人性化、经济性、多赢、自相似、改善、多样性、反省、机遇、流动、失败、冗余、质量、小步骤和接受责任等
看板方法
精益思想的具体实践:将表示软件开发任务的卡片或贴纸放在“看板墙”上用于表示开发进度,让开发流程变得可见
开发运维一体化
DevOps的技术实践
- 实现价值从开发到运维的快速流动
- 建立从运维到开发的持续、快速的反馈机制
- 建立持续的实验和学习的企业文化
重点在于持续集成、持续交付与持续部署
持续集成(CI)
主要目标:
- 使正在开发的软件始终处于可工作状态
- 更快地发现、定位和解决错误
- 提高软件质量,减少验证和发布新软件所需的时间
持续交付(CD)
任何代码变更提交后都能够:
- 自动运行构建和执行单元测试
- 自动将所有代码变更部署到测试环境和类生产环境
- 确保当代码变更部署到生产环境后可以正常工作,从而以可持续的方式快速向客户交付新的代码变更
如果代码没有问题,可以继续手工部署到生产环境中
持续部署(CD)
任何代码变更提交后都能够:
- 自动运行构建和执行单元测试
- 自动将所有代码变更部署到测试环境、类生产环境以及生产环境
实现从代码变更提交到生产环境部署的全流程自动化而无需人工干预
三者实现了部署流水线:将软件从开发完成到最终交付到用户手中的端到端的过程
从敏捷到开发运维一体化体现了现代软件开发什么样的特点?
现代软件开发的高质量和高效交付。
第五章 软件设计 超级大重点
建造一栋摩天大楼为什么要在施工之前进行设计?设计方案要考虑哪些方面的内容?如果是制作一个小板凳呢?
- 确保结构安全
- 规划空间布局
- 协调各专业施工
- 符合城市规划与法规要求
考虑方面:结构设计方面,功能布局方面,建筑外观方面,机电系统方面,消防安全方面,可持续发展方面
软件设计相关概念:
- 软件设计是软件需求与实现代码之间的桥梁,起着承上启下的作用;
- 应对系统复杂性的需要:强调分解为多个组成单元,并考虑交互关系和集成方案
- 应对系统演化性的需要:强调响应变化的成本
软件设计的目标
软件设计的主要目标是面向软件需求的要求规划软件实现方案,同时为软件开发的复杂性和变化性提供支持:
- 软件需求和实现代码之间的桥梁
- 应对软件开发的复杂性挑战
- 应对软件开发的变化性挑战
软件设计的层次(自下而上)
- 数据设计:软件的全局数据结构设计,包括数据实体及其属性和相互之间的关系。例如数据库或文件的方式
- 体系结构设计:决定系统的高层分解结构以及各种全局性的设计决策(如开发语言、异常处理策略)
- 组件接口设计:组件之间的交互接口设计,包括接口的功能和非功能性(如性能、吞吐量)要求、接口交互协议、接口操作及实现类定义等
- 组件级设计:组件内的具体设计方案,例如类及类之间关系、组件内部的局部数据结构和算法设计等
软件设计的思想:
分解与抽象
概念:分解和抽象是人类应对复杂性的两个基本手段,也是软件设计思维的重要基础
分解是指将软件不断分解为更细粒度的代码
抽象包括数据抽象和过程抽象
- 数据抽象:对于目标对象的数据化抽象描述
- 过程抽象:对一系列过程性步骤和指令序列的整体抽象
分解往往需要与抽象的思想相结合才能发挥应对复杂性的作用
软件抽象的选择:
- 好的抽象应该屏蔽底层细节,突出事物的本质特性,同时符合人的思维方式,从而实现降低复杂性的目标
- 由于针对抽象编程的实现方案不依赖于许多无关细节,因此好的抽象还能极大提高程序的可迁移性和可复用性
哪一种对于银行账户的抽象更合理?
![Pasted image 20250102002254.png]]
左边的抽象方案更符合人对于“账户”这个概念的理解,同时也能更好地适应变化:如果银行改变了账户取款的手续费策略,那么只需要修改取款(withdraw)操作的内部实现以调整手续费扣除策略,而调用该操作的客户端无需修改代码。
抽象数据类型
![Pasted image 20250102002432.png]]
更多的例子有栈,链表等等
软件体系结构
因为大规模软件系统(特别是网络化软件系统)需要更高层的设计考虑,因此提出软件体系结构,软件体系结构给出了软件系统的顶层设计,充分体现了分解与抽象的基本原则。
总体质量在很大程度上取决于体系结构设计
作用:
- 软件项目分工合作的基础
- 确认设计方案是否能有效满足需求
- 为满足未来演化和复用的需要而做出规划
- 作为多种候选技术方案对比选择的依据
- 识别并降低软件实现的风险
- 作为相关涉众沟通和交流的基础
关注点分离
关注点的概念:软件系统中所实现的某种功能或特性,反映不同涉众所关注和关切的方面
关注点分离是重要的设计原则:将软件系统的整体需求分解为尽可能小的关注点并分解到不同的模块单元(例如模块、包、类、方法等)中实现
![Pasted image 20250102005852.png]]
面临的主要问题:关注点散布和杂混
- 散布:与同一关注点相关的职责散布在多个模块单元中
- 混杂:同一模块单元中又混杂了多个关注点的职责
![Pasted image 20250102010014.png]]
模块化
概念:将整个产品或系统分解为大小合适、相对独立的模块。
作用:
- 使得各个模块的生产制造可以相对独立地进行
- 可以在不破坏整体结构的基础上实现模块替换和扩展
- 适用于软件设计的各个层次,包括软件体系结构中的组件、组件内的类一级的详细设计
是分解和抽象设计思想的集中体现、
模块化设计强调了模块独立性: - 高内聚:模块内部紧密相关共同完成所聚焦的职责
- 低耦合:模块之间松散关联,以来较少,相互影响较小
例如,高层设计的包独立,组件内部详细设计的类的相对独立
![Pasted image 20250102010606.png]]
信息隐藏
概念:模块(例如组件或类)将实现细节隐藏在内部,仅通过受限的接口对外提供访问。
体现的是模块化的低耦合:如果将模块内部的实现细节都对外暴露,那么即使模块分解得当也会造成不必要的模块间耦合
面向对象设计中的信息隐藏:分为两个方面
- 包对外可见的类的访问修饰符设为public,对外隐藏的类设置为protected
- 类中对外接口的一部分属性和方法设置为public,对外隐藏的属性和方法设置为private
好处:
- 通过屏蔽实现细节以及暴露抽象接口的方式降低了其他模块开发者对于当前模块的认知复杂性
- 通过抽象降低了内部实现细节的变化对于其他模块的影响
- 通过受控接口提供访问,可以更好地实现对于内部数据和操作的保护
校园一卡通系统中的校园卡类的两种设计方案哪一个更合理?
![Pasted image 20250102011330.png]]
- 左边的设计方案会带来不必要的耦合:访问校园卡类的其他类将依赖于校园卡类中的消费记录数组,该内部数据结构发生变化,那么访问校园卡类的其他类也将不得不修改;外部其他模块有可能对数组中的消费记录内容进行修改
- 右边的设计方案避免了这种不必要的耦合,只要接口方法(public方法)不变那么其他类就无需修改
重构
概念:在不改变代码外在行为的前提下,对代码作出修改以改进程序的内部结构
目的:提高软件的可维护性和可扩展性
可以在多个层面重构:基于系统整体行为不变,重构体系结构;基于软件模块整体行为不变,重构类的详细设计;基于类行为不变,重构内部代码,代码级重构。
软件经过不断修改后内部的设计和实现结构也会退化,重构可以阶段性地改进设计和实现质量,缓解内部质量退化的趋势。
软件重构是敏捷开发方法推崇的一种重要开发实践。强调避免过度设计,好的代码是演化而来,而非提前设计得来。
复用
概念:在不同软件系统中或同一软件系统的不同部分重复使用相同或相似的软件代码、软件设计或其他相关的软件知识
存在两个方面:
- 面向复用的软件开发:提供各种可复用的软件资产,重点考虑共性抽象与封装
- 基于复用的软件开发:利用已存在的可复用资产为当前项目的设计提供辅助
为什么企业软件开发过程中并不鼓励通过代码复制粘贴来实现软件复用?
这样会存在大量的相似代码,不利于程序的可读性和可维护性。同时,如果存在新的需求,不利于二次修改。并且测试时,所造成的工作量大。因此,基本上是通过API的形式对于软件进行复用。
面向对象设计 重点中的重点!!!!
面向对象设计方法在组件级设计以及组件接口设计上扮演着重要的角色
主要内容有:
![Pasted image 20250102012613.png]]
面向对象设计过程
面向对象软件设计的起点:
- 规模较大的系统:给定软件组件的设计要求,包括整体功能、对外接口等
- 规模较小的系统:整个系统的软件需求(使用面向对象方法实现整个系统)
基本的步骤:
1. 识别设计类
来源:
- 来自问题域中的设计类:所需满足的现实问题的抽象刻画与描述,包括名词性的业务实体对象,具有业务含义的处理过程这两种。
- 位于接口上的设计类:待开发软件系统与用户、硬件以及其他软件系统之间相应的接口
- 与基础设施相关的设计类:业务逻辑处理需要在计算、存储、网络等基础设施基础上才能实现。例如:实现数据库访问、跨网络或跨进程通信的设计类
判断潜在设计类的合理性:是否包含多个同类对象所共有的且是当前软件系统所需要的属性及相关操作
2. 明确设计类职责和协作
考虑各个设计类的职责以及类之间的协作关系。
难点在于类的职责分配,这也很大程度上决定了设计的质量。
类职责分配的基本原则是关注点分离,按照职责单一、相对独立的原则确定类与类之间的职责分配和边界划分。在关注点分离的基础上按照高内聚、低耦合的标准衡量每个类的独立性并进行调整。
为进一步降低类间耦合同时更好地支持未来可能的扩展,考虑通过引入抽象类和接口等手段进行一些共性抽象。
类与类之间的协作关系:凡是通过自身能力无法完成的部分职责就需要依赖于协作
3. 细化设计类内部细节
包括详细的属性和方法描述以及关键的内部数据结构和算法。
- 类属性需要细化的主要是访问修饰符、属性类型及初始值(默认值)
- 方法需要细化的主要是访问修饰符、参数及类型、返回值类型、前置及后置条件
- 内部数据结构和算法主要是类内部需要用到的局部数据结构和算法。一般通过流程图和伪代码的形式进行相应的描述
面向对象设计描述
主要任务是确定设计类、类的职责以及类间的交互关系。
UML类图用以描述面向对象的静态设计结构。
类:每个矩形代表一个类,上下部分分别是类名和方法。
接口:利用UML的构造型(stereotype)机制定义的一种特殊的“类”
关系:箭头表示类与类之间的各种静态结构关系:
- 虚线箭头表示类之间的依赖关系,具体表现为方法调用、属性访问等
- 菱形箭头表示类之间的聚集关系,具体表现为一个类引用另一个类的实例对象作为属性
- 实线空心三角形箭头表示类之间的继承关系,即父类与子类的关系。
UML顺序图可以表述在特定场景中类与类之间的动态交互关系。
例如,类与类之间的消息发送及其先后顺序等。
交互参与方:最上方的圆角矩形表述交互的参与方,是相关设计类的实例对象(一般用冒号:+类名用以表示)
时间线:每个参与方下面的虚线代表时间线,从上到下表示时间的先后顺序。
激活条:时间线上的矩形条表示激活条,表示所对应的参与方在此期间处于激活状态
不同参与方之间的横向箭头表示消息发送,包括多种消息类型:
- 实线三角形箭头表示同步请求消息,即一个参与方向另一个参与方发出请求消息并在收到返回之前进行阻塞等待
- 虚线线型箭头表示同步调用的返回
- 实线线型箭头表示异步请求消息,即一个参与方向另一个参与方发出请求消息而不进行阻塞等待。
UML状态机图通过状态转换的方式描述类的实例对象的行为。
状态:每一个圆角矩形表示一个状态,实心圆表示一个特殊的初始状态
转换关系:箭头表示状态之间的转换关系,箭头上的方法表示触发状态转换的方法调用
其他设计描述
- UML包图以包的形式描述更大粒度的模块之间的静态结构关系
- UML通信图在展示类的实例对象间关系的基础上描述对象间消息发送的顺序
- UML活动图描述由类方法调用构成的业务处理过程及算法流程
内聚和耦合
模块独立性常用内聚度和耦合度来衡量:
内聚
高内聚强调模块的职责应该明确切转移,并且所包含的内容都是与该职责密切相关不可或缺的部分
常见的内聚形态
![Pasted image 20250102031749.png]]
在可能的情况下,应当尽可能地实现内聚性较高的内聚形态,特别是功能内聚、层次内聚和通信内聚。
耦合
强调模块间的依赖金肯的少:理解和修改一个模块是不用过多考虑其他模块,同时修改后,对其他模块的影响也比较小。
优点:更容易单独取出用以复用。
常见的耦合形态
![Pasted image 20250102032519.png]]
![Pasted image 20250102032529.png]]
内容耦合消除的主要实现手段是信息隐藏;
共用耦合由于共享全局变量的使用而产生,危害主要在于其影响面、隐藏性和不可控性。
控制耦合带来的问题是需要根据相应参数的类型的变化而修改,因此,可以引入多态的概念来进行消除,建立参数的继承关系,调用抽象类,而不是对于具体的类进行相应的判断。
![Pasted image 20250102033046.png]]
面向对象设计原则
面向对象软件设计的一个主要目标是可维护性和可扩展性。
因此提出了SOLID设计原则(其中有两个L)
1. 单一职责原则
每个类、接口、方法都应该只具有单一的职责,应该只会因为一个原因发生变化。
强调的重点是类、接口、方法的内聚性
内聚性越高,它们的职责越单一,发生变化的原因也越集中
类与方法相比粒度更大,可以尽量让一个类具有更少、更加聚焦的职责
2. 开闭原则
一个模块应该对扩展开放,对修改封闭。要求软件增加新功能或新特性时应当通过扩展新的代码单元(如类、方法)而非修改已有的代码单元的方式来实现,原因是理解和修改现有代码的过程中面临较大的复杂性挑战,工作量较大且容易引入代码缺陷
开闭原则是一个重要而且基础性的设计原则,直接体现了软件设计的可扩展性的目标
实现的关键在于引入适当的抽象并为未来的扩展留下空间。
![Pasted image 20250102034105.png]]
3. 里氏替换原则
子类对象可以出现在任何父类对象出现的地方。
- 为了确保子类满足父类对外的所有约定(或称为契约)
- 这样按照父类对外声明的行为与之交互的其他类在遇到子类的对象时才不会发生问题
- 诸如多态这样的机制才能确保有效实现
可能存在下图中的情况:
![Pasted image 20250102041304.png]]
因此,在设计继承关系时需要按照里氏替换原则验证父类与子类之间的关系,如果不符合则应该避免使用继承关系
4. 迪米特法则
理解:每个类的直接“朋友”包括作为其属性、方法参数或返回值的对象,尽可能只与直接的“朋友”打交道,不要再跟其他类的对象打交道,例如在方法内引入其他类的对象作为局部变量
出发点是限制一个类与其他类的依赖关系:尽量通过已有的联系满足所需要的请求,而不要再引入新的类依赖
5. 接口隔离原则
多个服务于特定请求方的接口好过一个通用接口,不要强迫一个类依赖它不会使用的接口。
使用“万能”接口一方面不内聚,零一方面增加了耦合性以及开发人员理解的负担和接口实现与使用的发杂兴和依赖项
6.依赖转置原则
强调应该尽量依赖于抽象(例如抽象类、接口)而非具体(例如具体的实现类)
通过抽象我们可以只保留关键性的部分,而不用引入无关的部分(如不需要使用的方法)
依赖于抽象有利于长期演化和维护:
- 抽象的东西不容易变化,依赖于抽象的其他类受到变化的影响较小
- 抽象依赖为未来的扩展提供了方便,如果有新的实现方式,那么只要实现同样的接口,从而实现开闭原则的要求
即抽象不依赖于细节,细节依赖于抽象
面向切面的编程
面向切面的编程方法支持横切关注点解耦和模块化封装,为进一步改进软件设计提供了支持。
面向对象软件设计以包、类和方法实现层次化的模块分解以及相应的数据和操作封装,以关注点分类作为基本的设计思想。这会导致代码交织(与多个关注点相关的实现代码混杂在一个模块中)和代码散步(与同一个关注点相关的实现代码分散在多个模块中)的问题。
![Pasted image 20250102043649.png]]
![Pasted image 20250102043723.png]]
概念
- 切面(Aspect):实现关注点的模块化单元
- 通知(Advice):由切面所封装的、将插入到基本程序中指定地方执行的功能代码
- 连接点(Join point):基本程序结构或者执行流上的一种可以明确定义的位置
- 切点指示器(Pointcut Designator):为切面的定义提供了一种批量描述一系列连接点上的插入位置的机制
- 编织(Weave):将基本程序与切面集成到一起获得完整程序的过程
契约式设计
面向对象软件设计中的约定
面向对象设计中类的职责分配和协作关系确定是一个核心问题,这种基于类的设计分解要能够支持不同类的开发者在明确类职责的基础上独立进行开发,也要保证不同的类分别开发完成后能够顺利集成并正确实现整体系统设计要求。
类之间的接口约定
- 主要依赖于接口方法的语法声明,包括参数及其类型、返回值类型、抛出的异常等
- 这种语法声明不足以精确定义类之间的接口语义,从而埋下了接口理解不一致的隐患
接口定义模糊性
1)支持哪些运算操作不清楚
2)方法的操作符参数的精确定义不清楚
3)谁应该对除0操作进行检查不清楚
所带来的问题
- 还会导致出错之后难以定位问题根源以及厘清责任
- 接口的实现方需要承担更多的责任对各种潜在的问题(例如不合法的参数)进行检查,内部逻辑过于复杂,甚至调用链上的一系列代码单元重复对某些问题进行检查
基本思想:建立不同类(或者模块)之间的契约关系,以一种可检查的方式明确定义接口的实现方和调用方各自应当承担的“权利”和“义务”
常见的契约形式是对程序运行状态的断言,即关于输入参数、返回值、内部属性取值范围及其关系的布尔表达式。一般的契约内容包括以下三个方面:
- 前置条件(precondition):调用一个方法之前应当满足的条件
- 后置条件(postcondition):一个方法执行完成后应当满足的条件
- 不变式(invariant):一个软件元素(例如类或对象实例)在任何方法执行前后都应当一直满足的条件
契约的义务:
- 前置条件是方法的调用方需要确保的,即它们只能在某个方法的前置条件满足的情况下对其进行调用,否则出错责任在于调用方
- 后置条件是方法的实现方需要确保的,即如果它们的前置条件在调用之前是满足的那么在调用结束后它们的后置条件应该成立,否则出错责任在于被调用方
- 不变式则是一个软件元素所有方法的实现方都应当确保的,即任何方法的执行都不应当破坏不变式中的条件
![Pasted image 20250102102417.png]]
![Pasted image 20250102102408.png]]
设计模式
概念:设计模式是指针对一类相似设计问题的通用和参考性的设计方案,一般都经过大量的实践验证,能够较好地实现相关的设计目标
设计模式代表的是一种思想,具体使用的时候需要根据具体的问题和上下文进行相应的实例化。
设计模式分类: 这些设计模式大量运用了面向对象设计原则,其中最根本的一条是开闭原则。
![Pasted image 20250102104922.png]]
单例模式
应用场合:一个类只允许有一个对象实例。例如操作系统中的任务管理器和回收站、网站的计数器、金融交易的引擎、应用程序的日志引擎等。
要求访问这个类的对象的地方所获取的都是用一个对象的引用。
单例模式的特点:
- 将构造方法设为私有
- 内部包含一个类型为自身的静态成员对象(instance)
- 通过一个静态方法(getInstance)用于获取这个成员对象的引用
适配器模式
应用场合:一个类所需要的接口与另一个类所提供的接口不匹配,但功能相同或相近。可以通过适配器在二者之间进行转换和适配。
额外引入的适配器类(Adapter)一方面继承了Adaptee从而具备了该类所实现的能力,另一方面则实现了Target接口
![Pasted image 20250102111511.png]]
组合模式
应用场合:
- 需要处理的对象构成了一种表示整体部分层次的树状结构,例如文件系统中嵌套的目录结构、画图工具中嵌套的复合图形
- 客户端开发人员希望以一种统一的方式处理对象以及对象的组合,从而避免在代码中针对不同类型对象采取不同的处理策略(例如,对于原子对象直接调用操作,而对于复合结构则需要遍历其所包含的对象或下一级复合结构进行处理)
参考设计方案:
- 一方面允许将对象组织成嵌套层次结构,另一方面允许客户端代码以统一的方式处理对象以及对象的组合
- 复合对象可以包含一组子对象,其中既可以有原子对象又可以有下一级的复合对象
- 抽象的组件对象类上定义了某种操作方法operation。原子对象可以直接给出方法的实现,而复合对象则进一步调用所包含的下一级原子对象或复合对象的同一操作方法来实现
![Pasted image 20250102113358.png]]
策略模式
应用场合:
- 一些软件功能的实现涉及算法策略选择的问题(例如图形布局),而其中的算法策略存在很多种不同的选择
- 希望功能实现与算法策略之间实现松耦合的依赖,从而在更换算法或增加新算法时对功能实现的影响能够最小化
参考设计方案:
- 对算法策略进行封装,使得算法策略与使用它们的功能代码相互独立
- 抽象的算法策略类(Strategy)对具体的算法策略进行抽象和封装,继承该类的具体算法策略类提供各种具体实现
- 上下文类(Context)内部聚合一个算法策略类对象,通过这个对象的算法实现(algorithm)对外提供的统一的策略方法(strategyMethod)实现相关的算法功能(例如界面布局)
- 允许使用算法策略的客户端代码通过上下文类指定所需要的算法策略(通过setStrategy方法)并调用所需要的策略方法
![Pasted image 20250102113701.png]]
观察者模式
应用场合:
- 在包含用户界面的应用程序中,经常存在同样的数据对象通过多种不同的形式进行可视化展示的情况,例如关于道路交通的实时监控数据可以通过地图、表格以及各种统计图表等不同的形式来展现
- 数据的状态发生变化后各个展现视图都需要随之更新
- 各个视图都有可能发生变化,未来还有可能增加新的展现方式
- 按照单一职责原则以及开闭原则,我们希望数据管理与数据展现相分离,同时新增展现视图无需修改已有的代码
参考设计方案
- 负责数据管理的主题类(Subject)与负责显示逻辑的观察者(Observer)相分离
- 观察者通过对主题(即被观察者)的观察来实现及时更新
- 主题类中包含当前观察者的列表,当数据状态发生变化时可以调用观察者的通知方法(notify)来通知它们进行更新
![Pasted image 20250102114658.png]]
演化式设计
演化式设计
敏捷方法强调迭代和演化式的开发过程,通过短周期迭代不断交付可运行的软件从而持续获得用户反馈并不断调整开发计划。
问题:鼓励在迭代式的演化过程中逐步考虑相关设计问题,这使得设计决策似乎主要来自于开发过程中一堆即兴的决定。
计划设计
在开始前做好高层设计并逐步细化
问题:软件开发人员很容易会优秀到足以质疑设计人员给出的设计方案的程度。此外,软件开发中的需求变更几乎总是不可避免的
平衡计划设计与演化式设计
持续集成、测试、重构这三种实践已成为敏捷开发实践的重要组成部分。在此基础上,可以考虑将计划设计与演化式设计相结合,并找到一个合适的平衡点。
代码坏味道
侧重于软件重构。软件重构是实现演化式设计的关键,也是在迭代化开发过程中逐步引入设计决策的重要手段。
![Pasted image 20250102190722.png]]
![Pasted image 20250102190949.png]]
第六章 软件复用
软件复用的相关概念
从零开始的开发方式已经无法满足软件开发在快速交付、成本控制、质量保障等方面的要求。
软件复用已经成为一种重要的软件开发手段
重复利用已有的知识、经验或软件制品来开发新的软件产品
能够有效提高开发效率、降低开发成本、提高软件质量,并且缩短产品发布周期
软件复用所带来的变化
- 有力推动了通用软件资产的沉淀
- 极大促进了软件行业的分工
软件复用层次
组件级软件复用
主要目的是实现特定功能和特性,形式主要是软件组件。
这些软件组件实现特定的功能并明确定义了API,软件开发人员可以通过API调用的方式复用相关的功能实现。
可复用范围分为三类:
- 一方库:当前项目内的通用功能模块,一般通过项目内的接口定义为项目中的多个模块提供共性的功能实现
- 二方库:同一企业内所积累的通用功能模块,一般建议封装成软件组件并提供API描述同时由专人进行维护和升级
- 三方库:由开源社区或企业所提供的广泛授权使用的通用功能模块,一般都有规范的发布包和对应的API描述
框架级软件复用
主要目的是获得支撑应用运行的整体性框架,形式主要是各种软件开发框架。
在共性实现的基础上支持定制和扩展。如vue.js,SpringBoot
与组件级复用的区别:
- 组件级复用:应用代码通过调用组件的API实现软件复用
- 框架级复用:按照框架规范实现的应用代码被框架调用,因此其中经常会用到类似于依赖注入这样的设计思想
软件构件、模式与框架都可以被复用,但它们在复用的内容以及方式上有什么区别?
- 软件构件:针对特定功能提供可复用的实现,开发人员在自身已有的实现方案基础上调用构件实现局部功能
- 设计模式:一种抽象的设计思想,往往体现为参考设计方案(如用UML图表示),本身并没有代码实现,需要针对具体问题、参考其设计思想进行实现
- 软件框架:本身包含相对完整的设计以及核心实现,提供扩展和定制能力,开发人员针对特定应用的实现通过扩展点插入框架中,一般由框架来调用形成完整的应用实现
平台级软件复用
主要目的不仅包括获得特定功能和特性的实现以及整体框架支持,还包括获得软件应用的部署和运行支撑。
以小程序等形式支持应用开发、部署和运行
典型代表是各种互联网应用开放平台,例如:微信 、支付宝 、WeLink 平台
你是否在互联网开放平台上开发过小应用?如何理解平台在开发、测试、部署、运行等方面提供的支持?
自己思考,提供丰富的 API 接口,开发文档与指南,开发工具与 SDK,测试环境提供,测试数据支持,测试工具与指标反馈,一键部署功能,安全防护机制,高可用性保障
软件复用过程
包括生产者复用和消费者复用两个阶段,其中以可复用发软件制品作为桥梁
软件产品线
软件工程领域逐渐也形成了软件产品线的思想
- 针对特定领域中一系列具有共性特征的软件应用,通过对领域共性和可变性的把握构造一系列领域核心资产
- 面向应用需求的软件应用可以在这些核心资产基础上通过定制和扩展快速、高效地构造出来
你是否了解、使用或参加过开源项目?如何理解开源项目的运作机制及其价值?
项目发起与开源协议选择,代码托管平台与版本管理,社区协作与沟通机制,贡献流程与审核机制
组件级复用
- 软甲开发库复用:实现通用功能且经过良好封装的软件组件经过大量复用后,不仅可以提高开发效率、节约开发成本,而且其质量较高。存在明确的API以及文档
- 在线服务复用:某些功能和提供方内部数据有关,只能在线服务远程调用
- 接口描述规范:规范化描述相应的API接口,以确保正确调用。以资源为核心,通过HTTP动词来操作资源
第七章 软件体系结构
软件体系结构又被称为软件架构,是一个软件系统的高层设计结构。
软件体系结构决定了整个系统的整理样式、各个组成部分以及相互之间的关系,起到承上启下的作用:
- 为满足软件系统整体的功能性需求、质量需求和约束(如项目完成时间、需要符合的标准等)提供了一种解决方案
- 为后续更加具体的组件级设计(类似于楼层和房间内部设计)和实现(类似于建筑施工)提供了指导和参考
内容
- 一组软件组件:表示软件系统高层分解的结构元素,每个组件可以是简单的程序模块或类,或复杂的子系统以及扩展的数据库、中间件等
- 软件组件的外部属性:功能性属性(如接口、交互协议等)以及非功能性质量属性(如响应时间、吞吐量等)等组件外部属性
- 软件组件之间的关系:不同组件之间的静态依赖、动态交互以及运行时部署等关系
- 全局的实现约定:涉及多个组件、需要在系统全局作出约定的技术决策,例如实现语言、异常处理策略、共享资源使用方式、命名方式等
软件体系结构的作用
- 初步确认设计方案是否能有效满足需求
- 为满足未来演化和复用的需要而做出规划
- 多种候选技术方案对比选择的依据
- 识别并降低软件实现的风险
- 软件开发任务分工协作的基础
- 相关涉众沟通和交流的基础
软件体系结构决策
- 目标与条件:需要满足的一组目标以及相关的条件
![Pasted image 20250102195324.png]] - 效用函数:针对每一项目标或条件的评估函数,能够根据目标或条件的满足情况计算出效用值
![Pasted image 20250102195337.png]] - 约束:设计方案所需要满足的约束,其中有些约束是绝对的(即满足或不满足),而有些约束则具有一定的弹性(存在一定的协商空间)
![Pasted image 20250102195352.png]]
功能需求和非功能性需求的实现
功能性需求
实现功能性需求的方式相对直观,即将所要求的功能性需求无一遗漏地分配到某个软件设计单元(例如组件、模块、类等)上即可
非功能性需求
- 不仅取决于软件系统的组件如何划分而且还取决于一系列复杂的技术选型决策以及组件间交互设计
- 例如使用什么样的数据库、使用什么编程语言和开发框架、组件之间采用何种通信协议和交互模式(如同步或异步)、组件如何部署以及实现运行时伸缩等
![Pasted image 20250102195649.png]]
非功能性质量需求的冲突与权衡
- 不同的非功能性质量需求之间经常存在冲突,即实现某一个非功能性质量需求的设计可能会对另一个造成负面影响
- 软件体系结构设计经常需要在不同的非功能性质量需求之间进行权衡取舍
一个火车票订票系统如果有以下非功能性质量需求,那么要考虑哪些设计上的对策?
支持百万级的用户并发访问
系统每月宕机不超过1次
系统每天用户不可用的时间不超过1分钟
系统不易被黑客入侵
系统可以方便增加各种增值服务
![Pasted image 20250102200016.png]]
软件体系结构描述
通过“4+1”视图进行描述
![Pasted image 20250102200607.png]]
用例视图以软件系统的使用场景位纽带将其他四种视图联系到了一起。
用例视图
又称之为场景视图
- 对软件系统与外部参与者之间的典型交换序列的场景化描述,从最终用户的角度刻画了系统需要实现的功能
- 位于各体系结构视图的核心,是联系各种不同视图的纽带
- 包括各种关键的用例和场景,以免体系结构设计遗漏重要的功能需求
逻辑视图
- 反映软件分析和设计人员的关注点,即软件的业务模型以及逻辑分解结构
- 可以描述目标软件系统的领域模型(概念、实体及其之间的关系)、关键数据模型与数据流
- 还可以描述系统的高层组件(例如单体体系结构中的模块、微服务架构中的服务以及所复用的自有或第三方组件等)及其之间的关系
实现视图
又称之为开发视图
- 反映软件开发者以及开发管理者的关注点,即系统是如何分解实现以及构建得到最终交付制品(如二进制发布包)
- 描述代码的组织结构,即代码仓库以及代码目录结构
- 还可以描述构建(build)模型,即各个组件如何与所依赖的外部组件一起通过编译构建得到交付制品
运行视图
- 反映系统集成人员的关注点,即组件之间的动态交互行为以及其中的并发和同步设计
- 可以描述系统的进程划分和定义、组件等设计元素如何分布在不同的进程之中、进程之间如何进行交互和同步
- 对于分析系统的性能、并发性、分布性、可伸缩性、吞吐量、容错能力等质量属性具有重要的作用
部署视图
又称之为物理视图
- 反映安装部署人员的关注点,即软件系统如何交付并部署到运行环境中
- 可以描述交付和部署包的结构,即在构建得到的交付制品基础上如何进行组织和打包从而得到可以在运行环境中部署的软件包
- 还可以描述面向运行环境的软件部署方案,包括硬件节点类型、每类节点的设备要求、设备之间的网络连接方式、设备上的运行环境及参数配置、交付和部署包在硬件节点上的部署位置等
软件体系结构视图的作用阶段
![Pasted image 20250102201503.png]]
- 用例视图和逻辑视图主要指导需求分析和软件设计过程
- 逻辑视图还会为实现与测试提供软件高层逻辑结构方面的指导
- 实现视图指导实现与测试阶段的任务分工以及部分集成和构建活动,同时面向部署交付的需要定义交付制品
- 运行视图指导实现与测试阶段的进程划分与定义、进程间交互的集成与测试等,同时面向部署交付提供进程及交互关系定义
- 部署视图指导部署交付阶段的部署交付包的组织以及面向运行环境的软件部署方案
使用案例-----校园一卡通系统 重点重点,要理解如何画
PPT 18页
软件体系结构风格
以一种抽象的方式刻画了软件系统的整体设计样式,包括系统中的组件类型以及不同类型的组件之间的关系和组织方式等
经典的软件体系结构风格
C/S:
- 功能强大并针对特定操作系统专门开发的客户端软件
- 大部分业务逻辑可以在客户端实现,而服务器端可以相对简单甚至只提供数据库服务
- 优点:可以实现复杂的客户端逻辑并充分利用客户端计算机资源
B/S:
- 依赖于用户计算机上所安装的浏览器来展现界面并实现用户交互
- 大部分业务逻辑在服务器端实现
- 优点:无需安装客户端、升级方便
层次化体系风格:
概念:
- 每个层次都有明确的功能和职责划分,上层依赖于下层而下层则不能依赖于上层
- 通过明确定义的层间接口隔离不同层次内部实现方式的影响
- 体现了分解和抽象的设计原则:通过层次划分将功能实现分解到不同层次上;通过层间接口对每个层次的内部实现进行抽象
优点: - 清晰的层间接口定义和抽象有利于将开发任务解耦
- 清晰的层次划分和层间接口定义隔离了变更的影响
- 标准化的层间接口使得开发人员可以方便地替换其中的某一层,提高了可移植性
缺点: - 清晰的层次结构定义有时候较为困难
- 过多的分层可能对系统性能造成负面影响
- 高层实现不能直接访问底层资源,从而无法针对性地进行定制和优化
知识库体系结构风格(在人工智能应用当中,又被叫做黑板风格)
概念:
- 一种以数据为中心的体系结构风格
- 以数据的形式存在的知识在中心知识库中被集中保存和管理,围绕知识库的一组软件组件通过共享知识库间接进行交互
- 又被称为黑板风格,用于解决求解过程未知的人工智能问题
优点: - 实现简单并且能够依托成熟的数据库系统实现大量数据的共享
- 围绕中心知识库的各个组件之间耦合度很松,可以方便地实现组件的增加和修改而不会带来太大的副作用
缺点: - 当中心知识库数据量大到一定程度之后难以实现高效的数据访问和管理
- 中心知识库中的数据格式和规范对于开发有很大影响,一旦定义不合适可能会导致相关组件难以扩展和修改
管道和过滤器体系风格
![Pasted image 20250102234250.png]]
概念:
- 一种数据流体系结构,即其中的组件是按照数据流进行组织
- “过滤器”表示实现数据加工和处理的软件组件,而“管道”则表示这些组件之间的连接关系并掌握数据流的走向
- 组件间关系主要体现在输入输出数据流上,因此耦合相对较松
优点: - 适合于以数据传输和处理逻辑为主的系统(如数据批处理系统)
- 这种系统中包含一系列数据处理组件而且几乎不包含任何与用户交互的内容
缺点: - 人机交互性较强的软件系统,例如需要图形用户界面支持的系统,一般不适合采用管道—过滤器体系结构风格
分布式软件体系结构
分布式系统:
- 软件系统中包含多个通过网络连接的计算设备(称为节点)
- 其中的软件分布在不同的计算设备上并通过网络进行通信
分布式系统广泛应用的原因
- 移动终端(如智能手机)、传感器(如温度传感器)、智能设备(如智能冰箱)等网络化设备的大量使用
- 软件应用的用户数和使用频次越来越高,使得软件应用必须使用多台服务器甚至云计算平台来进行分布式部署
分布式软件体系结构设计具有更强的挑战性
需要考虑软件组件如何分布在不同的设备上并实现高效的分布式通信,同时还要确保一致性
例如,网上购物系统需要在多台服务器上部署与订单处理相关的软件组件以提高并行处理能力,同时也要设计相应的同步机制以确保一致性(如成功支付的订单一定送货)
分布式软件系统的质量要求
- 高性能
- 高可用量
- 可伸缩性
- 高安全性
常见问题:
- 为了确保不同服务器上商品数量的一致性,更新操作需要同时发送给相关的服务器,但如果其中有一些服务器或其网络发生故障而导致更新失败,那么就会导致更新成功和更新失败的服务器之间发生商品数量不一致的问题
- 如果要严格确保一致性,那么就要求相关服务器上的数据更新全部都成功后系统才能正常提供服务,由此可能导致系统的整体可用性下降(考虑各种服务器或网络故障问题)
软件体系结构设计经常要在多个相互冲突的目标之间进行权衡决策
分布式软件体系结构设计原则
GAP定理:
![Pasted image 20250103001600.png]]
![Pasted image 20250103001621.png]]
![Pasted image 20250103001640.png]]
![Pasted image 20250103001701.png]]
![Pasted image 20250103002732.png]]
![Pasted image 20250103002743.png]]‘
![Pasted image 20250103002755.png]]
![Pasted image 20250103002815.png]]’![Pasted image 20250103002836.png]]
第八章
![Pasted image 20250103003002.png]]
需求的重要性
- 反映客户、用户以及其他相关方的要求、诉求和愿望,同时也是检验最终交付的软件系统是否符合要求的重要依据
- 开发团队中的架构师、程序员等开发人员理解开发要求、考虑技术方案以及做出技术决策的重要参考
需求的来源
- 用户
- 客户
- 系统集成商
- 软件工程师
- 销售人员
- 公众与监管机构
需求的类型
- 功能性需求:功能性需求是指系统应向用户(人或其他系统)提供的功能
- 质量需求:质量需求定义了整个系统或系统组件、服务或功能的质量特性,其中有些需求针对系统整体,有些则针对特定的服务、功能或组件
- 约束:约束是一种限制了系统开发方式的组织或技术要求,包括文化约束(来源于系统用户的文化背景)、法律约束(来源于法律和标准)、组织约束、物理约束、项目约束等,此外按照作用对象还可以分为产品约束和过程约束
![Pasted image 20250103003821.png]]
![Pasted image 20250103003845.png]]
需求的质量要求
- 完整、无遗漏:所描述的需求完整、无遗漏地反映了相关涉众的要求和期望
- 明确、可测试:所描述的需求含义明确,可通过测试进行验证
- 严格、无歧义:所描述的需求表述严格,不同的人阅读之后不会产生不同的理解
- 一致、无矛盾:不同的需求描述之间保持一致,相互之间不存在矛盾
需求工程获取的过程
- 需求获取:识别相关涉众及文档资料、相关系统等其他需求来源,通过多种手段从这些来源那里获得各种需求信息并建立对于待开发系统的初步理解
- 需求分析:分析所收集的各种需求信息,抽取有用的需求陈述并不断进行细化,同时发现需求陈述中冲突或不一致的地方并对需求进行优先级排序
- 需求描述:通过标准的图形化或文本的方式对所获取和分析的需求陈述进行结构化组织和文档化描述
- 需求确认:通过格式审查和内容评审等方式检查文档化的需求描述是否符合标准格式要求、是否完整、准确地反映了相关涉众的期望和要求
以上这些活动并不是一个一次性的顺序过程而是一个迭代展开的持续性过程
需求管理
- 需求追踪管理
- 需求复用管理
- 需求变更管理
三种需求
- 用户需求:陈述用户的期望,即希望系统向各种用户提供什么样的服务以及系统运行应该满足哪些约束
- 系统需求:反映开发方与客户和用户协商后达成的关于系统所需要提供的服务、实现的功能及相关约束的一致意见
- 软件需求:系统需求中关于待开发的软件的功能、质量及约束等方面的描述
![Pasted image 20250103004621.png]]
需求分解与精化
软件开发项目一般都源自于一个改变当前现状的“愿景”(vision)
需求工程的主要目标是在现有的系统上下文环境中建立并实现愿景
概念:
- 愿景:给出了关于软件系统需要实现的目标的主观愿望
- 上下文环境:给出了目标实现可以利用的客观便利条件或必须考虑的客观约束
系统上下文环境:
- 处于待开发的软件系统边界之外且对目标系统的开发及其应用效果有影响的各种因素的综合
- 一般包括空间和物理环境、用户群体、文化和社会环境、软硬件和网络基础设施、第三方软件系统与服务等
![Pasted image 20250103004929.png]]
![Pasted image 20250103004944.png]]‘
![Pasted image 20250103004959.png]]![Pasted image 20250103010445.png]]
需求优先级
- 需求并非都是同等重要
- 需求优先级排序对于软件开发有着重要的作用
- 当项目开发资源或时间有限,难以按期完成所有需求时需要根据优先级对需求进行取舍
- 当需求发生冲突难以同时满足时,要按照优先级进行取舍
- 需求优先级的层次
- 基本需求:必须实现软件产品才能使用或者进入市场
- 期望型需求:用户、客户及相关涉众明确提出的需求,如果实现那么对于涉众的满意度有正面作用
- 兴奋型需求:用户、客户及相关涉众没有意识到某个需求或者没有期望该需求在系统中被实现,但如果实现了可以提高涉众的满意度
- 优先级很多时候也反映了需求之间的依赖关系:低优先级需求往往依赖于一些高优先级的需求
需求分析与描述
场景分析与描述
以一种直观和形象化方式描述和谈论待开发的软件系统将如何与各类用户打交道
概念
场景:场景(scenario)表示一组参与者(actor)与待开发系统之间的一系列交互步骤
用例:具有相同目标且交互过程相似的一组场景可以被组织为一个用例(use case)
案例:P35
用例参与者类型
- 由人来扮演的角色
需要与目标系统交互的各类用户,代表一种抽象的角色。例如食堂消费者、食堂窗口工作人员、图书馆读者等 - 外部设备
与目标系统交互的各种外部设备,包括传感器和执行器
外部设备拓展了软件系统感知和操控物理世界的能力
例如条码扫描枪、温度和湿度传感器、机械臂等 - 外部系统
与目标系统交互的其他外部软件系统,可以提供所需的服务或信息或者请求目标系统提供所需的服务或信息
例如提供在线支付服务的第三方在线支付系统 - 定时器
一种特殊的参与者,会定时触发预定义的处理逻辑
![Pasted image 20250103011241.png]]
识别为用例的情况
- 过程明确且完整:用例应当包含明确的交互过程,可以明确识别其中的交互步骤,交互过程有明确的开始和结束
- 可独立完成且不可再分:用例可以在不依赖其他用例的情况下独立完成,内部不可再细分得到更小的独立用例
- 对于用户有价值:用例所包含的交互过程如果完成对于相关用户有一定的价值
![Pasted image 20250103011438.png]]
![Pasted image 20250103011450.png]]
![Pasted image 20250103011502.png]]
类分析与描述
![Pasted image 20250103011651.png]]
分析类的类型
- 外部实体:产生或使用目标软件系统信息的外部实体,例如人员、设备、其他系统
- 事物:目标软件系统所管理的各种事物,例如订单、发票、商品
- 事件:发生的事件,一般具有时间戳,例如报警、来访
- 角色:由人扮演的各种角色,例如读者、管理员
- 组织单元:人类社会的各种组织单位,例如公司、部门、学校、院系
- 场地:现实世界的场地空间,例如房间、楼宇
- 结构:各种结构体,例如车辆、电器
分析类的选取标准
- 包含系统运行所需要的信息
- 包含多个而不是单个属性
![Pasted image 20250103012021.png]]
行为分析与描述
行为:系统或其一部分响应外部的事件激励而执行一些动作,同时伴随自身状态的变化
行为分析从系统本身而非场景分析中的外部参与者的角度了解到系统如何响应外部事件进行状态转换并执行各种动作的
行为的基本概念:
- 状态:行为主体所处于的某种情形,一般会维持一段时间(短则几秒甚至更短,长则几小时甚至更长)
- 事件:影响行为主体行为的外部或内部事件,推动行为主体状态的不断转换和各种动作的执行
- 状态转换:行为主体各种状态之间的转换,一般是在事件的激励下发生的,有时也会附加相应的条件要求
- 动作:维持某个状态期间或状态转换过程中执行的动作
![Pasted image 20250103012229.png]]
需求文档
![Pasted image 20250103012251.png]]
敏捷开发中的需求工程
增量地手机需求并以用户故事的形式写在卡片或白板上
用户故事的INVEST原则
- I(Independent):独立,能够单独进行实现
- N(Negotiable):可协商,要求不能定得太死,开发过程可变通
- V(Valuable):有价值,对于客户和用户有意义
- E(Estimable):可估算工作量及进度(不能估算往往意味着无法作出相对准确的计划,一般是因为粒度还不够小)
- S(Small):足够小,能在一个迭代内完成,不能跨越多个迭代
- T(Testable):可测试,能够对应设计测试用例来验证用户故事是否实现
![Pasted image 20250103012511.png]]
标签:实现,Pasted,image,复习资料,设计,软件,png From: https://www.cnblogs.com/cdag/p/18686936