原课程:北京邮电大学 软件工程 https://www.bilibili.com/video/BV1Bi4y1G7qY?spm_id_from=333.337.search-card.all.click
软件是计算机系统中与硬件相互依存的另一部分,它是包括程序,数据及其相关文档的完整集合。
软件危机(Software Crisis):指由于落后的软件生产方式无法满足迅速增长的计算机软件需求,从而导致软件开发与维护过程中出现一系列严重问题的现象。
(1) 软件开发计划难以制订。
(2) 软件开发费用和进度失控。
(3) 软件产品无法让用户满意。
(4) 软件产品的质量难以保证。
(5) 软件通常没有适当的文档资料。
(6) 软件通常是不可维护的。
(7) 软件成本在计算机系统总成本中所占比例逐年上升。
方法、工具、过程
在给定成本、进度的前提下,开发出满足用户需求且具有 可修改性、有效性、可靠性、可理解性、可维护性、可重用性、可适应性、可移植性、可追踪性和可互操作性 的软件产品。
软件需求 | Software Requirements |
---|---|
软件设计 | Software Design |
软件构造 | Software Construction |
软件测试 | Software Testing |
软件维护 | Software Maintenance |
软件配置管理 | Software Configuration Management |
软件工程管理 | Software Engineering Management |
软件工程过程 | Software Engineering Process |
软件工程工具和方法 | Software Engineering Tools and Methods |
软件质量 | Software Quality |
·P (Plan) : 软件规格说明(Specification)。规定软件的功能及其使用的限制;
·D (Do) : 软件开发。产生满足规格说明的软件;
·C (Check) : 软件确认。通过有效性验证以保证软件能够满足客户的要求;
·A (Action) : 软件演进。为满足客户的变更要求,软件必须在使用的过程中不断地改进。
事实上,软件工程过程是一个软件开发机构针对某一类软件产品为自己规定的工作步骤,它应当是科学的、合理的,否则必将影响到软件产品的质量。
软件生命周期(software life cycle )是指软件产品从考虑其概念开始,到该软件产品不再使用为止的整个时期,一般包括概念阶段、分析与设计阶段、构造阶段、移交阶段等不同时期。
在整个软件生命周期中贯穿了软件工程过程的六个基本活动:
① 制定计划: 确定要开发软件系统的总目标,给出它的功能、性能、可靠性以及接口等方面的要求;研究完成该项软件任务的可行性,探讨解决问题的可能方案;制定完成开发任务的实施计划,连同可行性研究报告,提交管理部门审查。
② 需求分析和定义:对待开发软件提出的需求进行分析并给出详细的定义。编写出软件需求说明书及初步的用户手册,提交管理机构评审。
③ 软件设计:设计是软件工程的技术核心。把已确定了的各项需求转换成一个相应的体系结构。进而对每个模块要完成的工作进行具体的描述。编写设计说明书,提交评审。
④ 程序编写:把软件设计转换成计算机可以接受的程序代码。
⑤ 软件测试:在设计测试用例的基础上检验软件的各个组成部分。
⑥ 运行/维护:已交付的软件投入正式使用,并在运行过程中进行适当的维护。
软件过程模型有时也称软件生命周期模型,即描述从软件需求定义直至软件经使用后废弃为止,跨越整个生存期的软件开发、运行和维护所实施的全部过程、活动和任务的结构框架,同时描述生命周期不同阶段产生的软件工件,明确活动的执行角色等。
九个传统软件生命周期模型:
.瀑布模型 .螺旋模型
.V模型和W模型 .喷泉模型
.原型方法 .构件组装模型
.演化模型 .快速应用开发模型
.增量模型
优点:
⑴ 软件生命周期的阶段划分不仅降低了软件开发的复杂程度,而且提高了软件开发过程的透明性,便于将软件工程过程和软件管理过程有机地融合在一起,从而提高软件开发过程的可管理性。
⑵ 推迟了软件实现,强调在软件实现前必须进行分析和设计工作。
⑶ 瀑布模型以项目的阶段评审和文档控制为手段有效地对整个开发过程进行指导,保证了阶段之间的正确衔接,能够及时发现并纠正开发过程中存在的缺陷,从而能够使产品达到预期的质量要求。
缺点:
⑴ 模型缺乏灵活性,特别是无法解决软件需求不明确或不准确的问题,这是瀑布模型最突出的缺点。因此,瀑布模型只适合于需求明确的软件项目。
⑵ 模型的风险控制能力较弱。成品时间长;体系结构的风险和错误只有在测试阶段才能发现,返工导致项目延期。
⑶软件活动是文档驱动的,文档过多会增加工作量,文档完成情况会误导管理人员。
V模型仍然将测试作为一个独立的阶段,所以并没有提高模型抵抗风险的能力。
(2) W模型——瀑布模型的变种
W模型由两个V型模型组成,分别代表测试与开发过程 ,两个过程是同步进行的。
1. 提出原因
完整准确的需求规格说明很难得到
通过加强评审和确认、全面测试也不能从根本上解决需求不稳定带来的问题。
2. 概述
原型:是指模拟某种产品的原始模型。软件原型是一个早期可以运行的版本,它反映最终系统的部分重要特性。
原型方法构造软件系统 :
原型化方法是在研究需求分析技术的过程中产生的,但也可以用于软件开发的其他阶段
3. 原型的种类(目的)
探索型:弄清对目标系统的要求
实验型:系统实现前考察系统的可行性
进化型:将原型扩展到开发过程,通过原型开发逐步实现所有系统功能。
4. 原型的使用策略
废弃策略:探索型和实验型
追加策略:进化型
原型不同于最终的系统,需要快速实现和运行,因此,原型可以忽略一切暂时不必关心的部分(抽象)
5. 优点
6. 缺点
8. 原型方法支持的软件生命周期
原型方法可以支持软件生命周期的不同阶段:
辅助或代替分析阶段 (确定需求)
辅助设计阶段 (确定设计方案的合理性)
代替分析与设计阶段
代替分析、设计和实现阶段
代替全部开发阶段 (典型的演化模型 )
项目开发初始阶段对需求的认识不够清晰,使得开发工作出现再开发在所难免。经验告诉我们:开发“两次”后的软件能较好地满足用户的要求。
演化模型主要针对需求不是很明确的软件项目
演化模型缺点:
结合了瀑布模型和演化模型的优点。
1. 增量模型优点
2. 增量模型缺点
针对大型软件项目的特点提出。
螺旋模型沿着螺线旋转,在四个象限上分别表达了四个方面的活动,即:
螺旋模型适合于大型软件的开发;然而风险分析需要相当丰富的评估经验,风险的规避又需要深厚的专业知识,这给螺旋模型的应用增加了难度。
喷泉模型认为软件开发过程具有两个固有的本质特征:
迭代:多次重复、演进。
无间隙:各阶段间无明显的界限。支持分析和设计结果的自然复用。
适用:面向对象的软件开发过程。对象概念的引入,对象及对象关系在分析、设计和实现阶段的表达方式的统一,使得开发活动之间的迭代和无间隙性能够容易地实现。
构件组装模型本质上是演化的,开发过程是迭代的。
构建组装模型由五个阶段组成:
需求定义和分析
软件体系结构设计
构件开发
应用软件构造
测试和发布
软件的开发过程步骤如下:
(1)定义和分析需求;
(2)标识本项目需要什么构件;
(3)从库中查找构件或相似的构件;
(4)如果可用转(5),否则自行开发或修改,确认后入库;
(5)构造为新系统作第m次迭代;
(6)测试、确认。
快速应用开发(Rapid Application Development,RAD)是一个增量型的软件开发过程模型,采用构件组装方法进行快速开发。
RAD模型包含如下阶段:
(1)业务建模:通过捕获业务过程中信息流的流动及处理情况描述业务处理系统应该完成的功能。回答以什么信息驱动业务过程运作? 要生成什么信息? 谁生成它? 信息流的去向? 由谁处理? 可以辅之以数据流图。
(2)数据建模:对于支持业务过程的数据流,建立数据对象集合,定义数据对象属性,与其它数据对象的关系构成数据模型,可辅之以E-R图。
(3)过程建模:定义如何使数据对象在信息流中完成各业务功能。描述数据对象的增加、修改、删除、查找。即细化数据流图中的处理框。
(4)应用生成:利用第四代语言(4GL)写出处理程序,重用已有构件或创建新的可重用构件,利用环境提供的工具,自动生成,构造出整个的应用系统。
(5)测试及迭代:由于大量重用,一般只作总体测试,但新创建的构件还是要测试的。当一轮需求完成快速开发后,可以迭代进入下一轮需求的开发。
RUP(Rational Unified Process)是一个面向对象的基于web的程序开发方法论。
RUP既是一种软件生命周期模型,又是一种支持面向对象软件开发的工具,它将软件开发过程要素和软件工件要素整合在统一的框架中。
(1) RUP的基本结构
RUP是一个二维的软件开发模型。
横轴在时间上将生命周期过程展开成四个阶段(Phase),每个阶段特有的里程碑(Milestone)是该阶段结束的标志,每个阶段里又划分为不同的迭代(Iteration),体现了软件开发过程的动态结构。
纵轴按照活动的内容进行组织,包括活动(activity)、活动产出的工件(artifact)、活动的执行角色(worker)以及活动执行的工作流(workflow),体现软件开发过程的静态结构。
阶段目标:通过业务用例(Business Use Case)了解业务并确定项目的边界,包括项目的验收规范、风险评估、所需资源估计、阶段计划等。
要确定项目边界,需识别所有与系统交互的外部实体,主要包括识别外部角色(actor)、识别所有用例并详细描述一些重要的用例。
Milestone:软件目标里程碑。包括一些重要的文档,如项目愿景(vision)、原始用例模型、原始业务风险评估、一个或者多个原型、原始业务场景等。
需要对这些文档进行评审,以确定正确理解用例需求、项目风险评估合理、阶段计划可行等。
2 - 细化阶段
阶段目标:分析问题领域,建立适合需求的软件体系结构基础,编制项目计划,完成项目中技术要求高、风险大的关键需求的开发。
Milestone:体系结构里程碑。包括风险分析文档、软件体系结构基线(baseline)、项目计划、可执行的进化原型、初始版本的用户手册等。
通过评审确定软件体系结构的稳定性、确认高风险的业务需求和技术机制已经解决、修订的项目计划可行等。
3 - 构造阶段
阶段目标:将所有剩余的技术构件和稳定业务需求功能开发出来,并集成为产品,所有功能被详细测试。从某种意义上说,构造阶段只是一个制造过程,其重点放在管理资源及控制开发过程以优化成本、进度和质量。
Milestone:运行能力里程碑。包括可以运行的软件产品、用户手册等,它决定了产品是否可以在测试环境中进行部署。
要确定软件、环境、用户是否可以开始系统的运行。
4 - 移交阶段
阶段目标:软件产品正常运行并交付用户使用。交付阶段可以跨越几次迭代,包括为发布做准备的产品测试,基于用户反馈的少量调整。
Milestone:产品发布里程碑。包括维护和售后支持文档手册等。
要确定最终目标是否实现,是否应该开始产品下一个版本的另一个开发周期。
(2) RUP的迭代增量开发思想
RUP是以用例为驱动,软件体系结构为核心,应用迭代及增量的新型软件生命周期模型
RUP的每一个阶段可以进一步划分为一个或多个迭代过程,从一个迭代过程到另一个迭代过程增量形成最终的系统。
RUP是融合了喷泉模型和增量模型的一种综合生命周期模型 。
RUP将整个项目的开发目标划分成一些更易于完成和达到的阶段性小目标。每一次迭代就是为了完成一定阶段性小目标而从事的一系列开发活动,包含需求、设计、实施(编码)、部署、测试等。
(3) RUP的核心工作流
6个核心过程
工作流(Core Process Workflows)
3个核心支持
工作流(Core Supporting Workflows)
(4) RUP的最佳实践Best Practice
(1) 定义
敏捷方法的主要特点就是具有快速及灵活的响应变更的能力
敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。在敏捷开发中,软件项目的构建被切分成多个子项目,各个子项目的成果都经过测试,具备集成和可运行的特征。换言之,就是把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。
敏捷方法很多,包括极限编程(XP)、 Scrum、功能驱动开发(FDD)、水晶、净室开发等多种方法,这些方法本质实际上是一样的,都遵循“敏捷宣言”原则。
(2) 极限编程 (eXtreme Programming )
XP是一种轻量级的软件开发方法,是一种以实践为基础的软件工程过程和思想。
它使用快速的反馈,大量而迅速的交流,经过保证的测试来最大限度的满足用户的需求。
XP强调用户满意,开发人员可以对需求的变化作出快速的反应。
XP的工作环境
每个参加项目开发的人都将担任一个角色(项目经理、项目监督人等等)并履行相应的权利和义务。
用户也是项目组的一部分。
所有人都在同一个开放的开发环境中工作。
XP的需求分析
XP的设计
从开发的角度来看,XP内层的过程是一个基于Test Driven Development周期,每个开发周期都有很多相应的单元测试。
随着这些测试的进行,通过的单元测试也越来越多。通过这种方式,客户和开发人员都很容易检验,是否履行了对客户的承诺。
同时,XP还大力提倡设计复核(Review)、代码复核以及重整和优化(Refectory),所有的这些过程其实也是优化设计的过程;
XP的编程
XP提倡配对编程(Pair Programming),而且代码所有权是归于整个开发队伍(Collective Code Ownership)。
程序员在写程序和重整优化程序的时候,都要严格遵守编程规范。
任何人都可以修改其他人写的程序,修改后要确定新程序能通过单元测试。
XP的测试
XP提倡在开始写程序之前先写单元测试。
1. 系统分析
系统分析是一组统称为计算机系统工程的活动。它着眼于所有的系统元素,而不仅仅是软件。
系统分析主要探索软件项目的目标、市场预期、主要的技术指标等,用于帮助决策者做出是否进行软件项目立项的决定。
2. 可行性分析(Feasibility-study)
可行性分析的目的不是解决问题,而是确定问题是否值得去解决。
针对项目的目标和范围进行概要的分析和研究,探索问题域中的核心问题及其相应的解决方案,进一步为决策者提供经济、技术甚至是法律上可行性的分析报告。
1. 需求的定义
宽泛地讲,需求来源于用户的一些“需要”,这些“需要”被分析、确认后形成完整的文档,该文档详细地说明了产品“必须或应当”做什么
通俗的软件需求定义:针对待开发的软件产品,软件开发人员通过对软件产品的拥有者和使用者的交流和调研,获取相关的业务职能、业务知识和业务流程等信息,并对这些信息进行分析和整理后形成的有关该软件产品必须提供的功能和性能等指标的规格描述。
2. 需求的不确定性
需求的不确定性反映了需求的重要作用,需求分析的优劣对软件产品的质量影响最大。
软件需求分析的任务是:准确地定义新系统的目标,回答系统必须“做什么”的问题,并编制需求规格说明书。
需求分析的目标: 就是借助于当前系统的逻辑模型导出目标系统的逻辑模型,解决目标系统的 “做什么” 的问题。
分析建模的操作性原则:
需求分析的工程化原则:
软件的需求分析是一系列复杂的软件工程活动,为了便于对需求进行更好的管理,人们把所有与需求直接相关的活动通称为需求工程。
需求工程中的活动可分为两大类,一类属于需求开发,另一类属于需求管理。
需求分析阶段的工作可以分成以下几个主要方面:
需求开发:
- 需求获取—《用户需求说明书》User Requirements Statements:需求沟通、需求获取
- 需求定义—《软件需求规格说明书》software requirements specification:需求分析与综合;需求建模;制定需求分析规格说明
需求管理:
- 需求确认—《需求评审报告》和书面承诺:需求评审、需求承诺
(1)需求获取的对象:用户和客户。
用户:使用软件的人员
客户:购买软件的人员
客户与最终用户可能是同一个人也可能不是同一个人 。
需求获取难点:
用户无法清楚地表达需求
需求分析员必须设法搞清楚用户真正的需求,这是需求分析员的职责。
需求的理解问题
需求分析员和用户都有可能误解需求,需求确认工作(属于需求管理)必不可少。
用户经常变更需求
需求变更并不可怕,可怕的是需求变更失去控制,导致项目混乱。
(3) 需求获取的准备工作
起草需求调查问题表,将调查重点锁定在该问题表内。(调查什么? )
确定需求调查的方式 。(如何调查?)
确定调查的时间、地点、人员等,撰写需求调查计划 。(“何人”在“何时”调查? )
需求调查的方式
(4) 需求获取与记录
在调查过程中随时记录(或存储)需求信息,建议采用表格的形式。
(5) 撰写用户需求说明书
需求分析员对收集到的所有需求信息进行分析,消除错误,归纳与总结共性的用户需求。然后按照指定的文档模板撰写《用户需求说明书》。
《用户需求说明书》不同于最终的《软件需求规格说明书》
前者主要采用自然语言来表达用户需求,其内容相对于后者而言比较粗略,不够详细。
后者是前者的细化,更多地采用计算机语言和图形符号来刻画需求,软件需求是软件系统设计的直接依据。
两者之间可能并不存在一一影射关系
(6) 软件需求类别
.功能需求 .性能需求
.环境需求 .可靠性需求
.安全保密要求 .用户界面需求
.资源使用需求
.软件成本消耗与开发进度需求
.预先估计以后系统可能达到的目标
除了上述需求之外,还需要考虑一些其他的非功能性的需求并进行相应的分析。
2. 软件需求定义
目的 | 定义准确无误的软件产品需求,产生《软件需求规格说明书》。 |
---|---|
角色与职责 | 需求分析员定义软件需求。客户与最终用户确认软件需求。 |
启动准则 | 《用户需求说明书》已经撰写完成。 |
输入 | 《用户需求说明书》 |
主要步骤 | 第一步:细化并分析用户需求;第二步:撰写软件需求规格说明书;第三步:软件需求确认 |
输出 | 《软件需求规格说明书》 |
结束准则 | 《软件需求规格说明书》已经撰写完成。开发方和客户方已经对产品需求进行了确认。 |
度量 | 需求分析员统计工作量和上述文档的规模,汇报给项目经理。 |
(1) 需求分析与综合
需求获取之后,对比较复杂的用户需求进行建模分析,帮助软件开发人员更好地理解需求。
在模型基础上,逐步细化所有的软件功能,找出系统各元素之间的联系、接口特性和设计上的限制,分析它们是否满足功能要求,是否合理。
依据功能需求,性能需求,运行环境需求等,剔除其不合理的部分,增加其需要部分。最终综合成系统的解决方案,给出目标系统的详细逻辑模型。
建模可以帮助软件开发人员更好地理解需求。
它着重于描述系统必须做什么、而不是如何去做系统。
该过程需要给出系统的逻辑视图(逻辑模型)以及系统的物理视图(物理模型)。
常用的建模分析方法
(3) 编制需求分析文档
好的《软件需求规格说明书》应具备如下属性:
正确、清楚、无二义性、一致、必要、完备、可实现、可验证、确定优先级、阐述“做什么”而不是“怎么做”。
目的 | 开发方和客户对需求文档进行评审,并作书面承诺。 |
---|---|
角色与职责 | 开发方和客户共同组织人员对需求文档进行评审。双方负责人对需求文档作书面承诺,使之具有商业合同效果。 |
启动准则 | 需求文档如《用户需求说明书》和《软件需求规格说明书》已经完成。 |
输入 | 需求文档如《用户需求说明书》和《软件需求规格说明书》 |
主要步骤 | 第一步:非正式需求评审 第二步:正式需求评审 第三步:获取需求承诺 |
输出 | 《需求评审报告》和书面的需求承诺 |
结束准则 | 需求文档通过了正式评审,并且获得开发方和客户的书面承诺。 |
度量 | 项目经理统计工作量和上述文档的规模。 |
需求分析评审的主要内容:
评判需求优劣的主要指标有:
正确性、清晰性、无二义性、一致性、必要性、完备性、可实现性、可验证性。
提纲
UML概述
UML中的图
面向对象分析概述
用例建模
创建领域模型
绘制系统顺序图
创建系统操作契约
UML:统一建模语言 ,UML 是一种标准的图形化建模语言,它是面向对象分析与设计的一种标准表示。
1. UML的目标
为建模者提供现成的、易用的、表达能力强的可视化建模语言,以开发和交换有意义的模型;
提供可扩展性和特殊化机制以延伸核心概念;
与具体的实现无关,可应用于任何语言平台和工具平台;
与具体的过程无关,可应用于任何软件开发的过程;
支持更高级的开发概念,例如构件、协作、框架和模式,强调在软件开发中对架构、框架、模式和构件的重用(UML 1.4规范);
与最好的软件工程实践经验集成;
可升级,具有广阔的适用性和可用性;
推动对象工具市场的成长。
2. UML的视图和图
五类不同视图:
每一种UML的视图都是由一个或多个图组成的:
视图和组成视图的图之间的对应关系:
用例方法是当今广泛使用的用于发现和记录系统功能性需求的方法
**用例的主要思想是:**以用户目标(即用户希望系统能为他带来哪些有价值的结果)为出发点去考虑系统的功能和特性,并用用例进行描述,专注于考虑系统怎么才能增加价值和实现用户目标。
用例将系统的特性和功能放到面向用户目标的语境中去考虑,从而能使识别出来的功能是真正为用户提供价值的功能。
类之间关系的表示
UML中类之间的关系可分为:依赖、关联、聚合、组合和继承
(1)依赖
依赖是一种使用的关系,即一个类的实现需要另一个类的协助,所以依赖关系通常是单向的。UML中使用带箭头的虚线表示依赖关系。
依赖具有偶然性、临时性,是非常弱的关系。简单理解就是类A使用到了类B,使用完毕后关系解除。
(2)关联
关联是一种拥有的关系,它使一个类知道另一个类的属性和方法,是一种长期性、相对平等的关系
关联可以有双向(实线)和导航(单向箭头),关联的两端可以标注重数(基数),表示类之间的数量对比关系
关联类:和类一样,关联也可以有自己的属性和操作。此时,这个关联实际上是个关联类(association class)
(3)聚合(aggregation)
聚合是表示整体的类和表示部分的类之间的**“整体–部分”关系**,是一种强类型的关联。在聚合关系中,把作为**“整体”的类称为聚集(aggregate),作为“部分”的类称为成分**
聚合关系中的整体和部分之间用带空心菱形箭头的连线连接,箭头指向整体。
(4)组合(composition)
组合是更强类型的聚合,要求部分的生存周期取决于整体的生存周期,部分不能脱离整体而单独存在,每个部分只能属于一个整体。
除了菱形是实心之外,组合和聚合的表示法相同
(5)继承(generalization)
继承也称泛化,是面向对象描述类之间相似性的一种重要机制
父类与子类的泛化(generalization)关系图示为一个带空心三角形的直线,空心三角形紧挨着父类。
类图表示类以及类之间的关系,对象图表示在某一时刻类的具体实例和这些实例之间的具体连接关系。
顺序图是一种详细表示对象之间以及对象与参与者之间交互的图,它由一组协作的对象(或参与者)以及他们之间可发送的消息组成,强调消息之间的顺序。
顺序图是二维的,其中,垂直方向表示时间,水平方向表示不同的对象或参与者。
协作图是一种强调发送和接收消息的对象结构组织的交互图,显示围绕对象以及它们之间的链而组织的交互。
协作图由对象、链以及链上的消息构成,其中也可以有参与者。
协作图有两点不同于顺序图: 协作图有链和消息序号。
顺序图和协作图可以相互转换,而不丢失语义信息,因为这两种图都共享相同的基本模型。它们统称为类和对象的 “交互图” 。
1. 什么是OOA
**面向对象分析(Object-Oriented Analysis,简称OOA)**就是运用面向对象的方法进行系统分析,是软件生命周期的一个阶段,具有一般分析方法共同具有的内容、目标及策略,强调运用面向对象方法,对问题域和系统职责进行分析和理解,找出描述问题域及系统职责所需的对象,定义对象的属性以及它们之间的关系,目标是建立一个符合问题域、满足用户需求的OOA模型。
2. OOA与OOD的职责划分
OOA针对现实世界中的问题域与系统职责,用面向对象的方法建立起针对问题域和系统职责的模型,作为分析的结果。
OOA模型不考虑与系统的具体实现相关的因素,独立于具体的实现环境。
OOD则是针对系统的具体实现,运用OO方法进行系统设计。
一是根据实现条件对OOA模型做某些必要的调整和修改,使其成为OOD模型的一部分
二是针对具体实现条件,建立人机界面、数据存储和控制驱动等模型。
3. OOA过程
主要包括以下活动:
用例建模的基本过程:
第1步.确定系统边界。
第2步.识别主要参与者。
第3步. 根据主要参与者目标,识别和定义用例。
用例之间的关系有包含关系、扩展关系和继承关系,在此重点介绍前两种关系。
(1)包含关系(include)
一部分行为经常会出现在多个用例中,为了避免重复,可以创建一个子功能级别的用例,并让其他的用例包含它。
一个用例可以包含多个用例,一个用例也可被多个用例包含。
(2)扩展关系(extend)
问题:由于某种原因已有的用例文本不能被修改(例如该用例文本已经是基线),但是可能又要为种种新的扩展场景和条件步骤不断修改用例
使用扩展关系可以解决这个问题。其思路是创建一个扩展或附加用例,在该用例中描述在什么情况下,从基用例什么地方开始扩展基用例的行为
使用场合:(多个)基本用例中的某些场景存在相同的条件判断的情况,可以将其抽取出来作为基本用例的子用例;
用例描述
对用例的描述,可以用自然语言,也可以采用用户自定义的语言。
为了更清楚地说明问题,也可以采用面向对象的类图、交互图、状态图或活动图来做进一步的描述。由于现在还只是需求分析阶段,只是在概念上使用这些图。
(1)定义
领域模型:针对某一特定领域内概念类或者对象的抽象可视化表示。
主要用于概括地描述业务背景及重要的业务流程,并通过UML的类图和活动图进行展示,帮助软件开发人员在短时间内了解业务。
(2)创建步骤
领域模型的创建步骤如下:
第1步 识别或抽象出领域的概念类或对象;
第2步 建立概念类之间的关系;
第3步 设置概念类的关键属性。
识别概念类
添加关联
添加属性
一个系统顺序图用来表示在用例的一个特定场景中,外部参与者产生的事件、事件的顺序以及系统之间的事件。
在系统顺序图中,所有的系统都被当作黑盒,图的重点是描述参与者和系统之间、或者系统和系统之间的事件,因此称这些事件为系统事件。系统事件对于理解系统要具备怎样的行为是很有帮助的。
系统事件通常是参与者主动向系统发出的。为了识别系统事件,需要从用例的主要成功场景以及频繁或复杂的替代场景中寻找系统事件,建立系统顺序图。
系统事件的发生将会触发系统操作,系统操作可以通过发现系统事件来识别。
系统操作使用和系统事件相同的名字,以明确表示是哪个系统事件引发的该系统操作。系统操作的参数同系统事件。
创建契约的指导原则:
提纲
分析模型的结构
软件需求规格说明书
Structured Analysis(SA):面向数据流进行需求分析,适合于数据处理类型软件的需求分析。
为了把用户的数据要求清晰明确地表达出来,软件开发人员通常建立一个概念性的数据模型(也称为信息模型)。
概念性模型是一种面向问题的数据模型,是按照用户的观点来对数据和信息建模。它描述了从用户角度看到的数据,反映了用户的现实环境,但与在软件系统中的实现方法无关。
最常用的表示概念性数据模型的方法,是实体/关系方法(Entity Relationship Approach)。这种方法用ER图描述现实世界中的实体,而不涉及这些实体在系统中的实现方法。用这种方法表示的概念性数据模型又称为ER模型。
数据对象(实体)、属性和关系
一对一(1:1)
:(实体)A的一次出现可以并且只能关联到(实体)B的一次出现,B的一次出现只能关联到A的一次出现。一对多(1:N)
:(实体)A的一次出现可以关联到(实体)B的零次、一次或多次出现.但B的一次出现只能关联到A的一次出现。多对多(M:N)
:(实体)A的一次出现可以关联列(实体)B的一次或多次出现.同时B的一次出现也可以关联到A的一次或多次出现。ER图的主要目的是以图形的形式表示实体以及实体之间的关系。
ER图标识了一组基本的构件:实体、属性、关系。
规范化的目的是消除数据冗余,即消除实体表中数据的重复。
消除多义性,使关系中的属性含义清楚、单一;
使关系单纯化,让每个数据项只是简单的数或字符串,方便操作。
使数据的插入、删除与修改操作可行且方便;
使关系模式更灵活,易于实现接近自然语言的查询方式。
关系规范化的程度通常按属性间的依赖程度来区分,并以范式(Normal Form,NF)来表达。范式是符合某一种级别的关系模式的集合。
目前关系数据库有六种范式。一般说来,数据库只需满足**第三范式(3NF)**就可以达到设计的要求了。
当数据或信息“流”过计算机系统时将会被系统的功能所处理、加工或变换后再将处理或变换后的数据从系统输出。
数据流图是描述信息流和数据从输入移动到输出时被系统的功能变换的图形化技术。
数据流图可以被用来抽象地表示系统或软件,既能提供功能建模的机制,也可提供数据流建模的机制,并可以自顶向下的机制表示层级的功能细节和数据变换细节。
DFD也被称为数据流图(Data Flow Diagram)或泡泡图(Bubble Chart)。
(2) 数据流与加工之间的关系
在数据流图中,如果有两个以上数据流指向一个加工,或是从一个加工中引出两个以上的数据流,这些数据流之间往往存在一定的关系。
(3) 分层的数据流图
为表达稍为复杂的实际问题,需要按照问题的层次结构进行逐步分解,并以分层的数据流图反映这种结构关系。
在多层数据流图中,可以把顶层流图、底层流图和中间层流图区分开来。
(4) 数据流图的画法
自外向内,自顶向下,逐层细化,完善求精。
(5) 数据流图的检查和修改原则
1) 数据流图上所有图形符号只限于四种基本图形 元素;
2) 数据流图的主图必须包括前述四种基本元素, 缺一不可;
3) 数据流图的主图上的数据流必须封闭在外部实 体之间,外部实体可以不只一个;
4) 每个加工至少有一个输入数据流和一个输出数 据流;
5) 在数据流图中,需按层给加工框编号,表明该 加工处在哪一层,以及上下层的父图与子图的 对应关系;
6) 任何一个数据流子图必须与它上一层的一个加工对应,两者的输入数据流和输出数据流必须一致。此即父图与子图的平衡。它表明了在细化过程中输入与输出不能有丢失和添加。(数据流图的平衡原则)
7) 子图相对于父图,添加一些新的“加工”和新的数据流,如果发现有新的数据存储,更新上层各级父图,直到顶层;
8) 图上每个元素都必须有名字。表明数据流和数据文件是什么数据,加工做什么事情;
9) 数据流图中不可夹带控制流。因为数据流图是实际业务流程的客观映象,说明系统“做什么”而不是要表明系统“如何做”,因此不是系统的执行顺序,不是程序流程图;
10) 初画时可以忽略琐碎的细节,以集中精力于主要数据流。
(6) 数据流图示例——医院就诊管理系统
挂号:挂号处的挂号人员接受病人的就诊请求,根据门诊科室各医生病人的排队情况,分配合适的医生,记录并打印挂号凭据,收取挂号费,完成挂号请求。
问诊:医生根据挂号的次序对病人进行病情诊断,根据挂号单据及病历号获取该病人的历史病历,然后问诊结果记录在病历当中并开具相应的处方(可根据系统提供的药品进行选择),打印处方交给病人完成一次问诊。
收费:收费员根据病人提交的处方所列出的药品种类和数量进行收费,之后打印收费清单并找零钱,完成一次收费过程。
取药:药剂师根据盖章后的处方,进行核对并修改处方状态,将药品交付给病人。病人取药后离开医院,完成一次就医过程。
!](https://img-blog.csdnimg.cn/3d642a4b69f7427f80e7d9d99d1d3da2.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Zik5qGD5a2Q,size_20,color_FFFFFF,t_70,g_se,x_16)
分层次构建数据流图
顶层数据流图 (确定四个要素)
数据存储与加工之间,在表示上只需加上双向箭头,用来表明它们之间的数据交互,无须特别表示数据流的内容,可在数据词典中说明
(7) 实时系统的数据流图
除了原有的数据流之外还引入了控制流及连续的数据流等符号。
这种扩展可以适应实时系统提出的以下要求:
① 在时间连续的基础上接收或产生数据流;
② 贯穿系统的控制信息和相关的控制处理;
③ 在多任务的情况下可能会遇到同一个加工的多个实例;
④ 系统状态以及导致系统状态迁移的机制。
为了直观地分析系统的动作,从特定的视点出发描述系统的行为,需要采用动态分析的方法。
最常用的动态分析方法:
(1) 状态迁移图 (STD)
利用状态迁移图(STD)或状态迁移表来描述系统或对象的状态,以及导致系统或对象的状态改变的事件,从而描述系统的行为。
每一个状态代表系统或对象的一种行为模式。状态迁移图指明系统的状态如何相应外部的信号(事件)进行变化。
在状态迁移图中,用圆圈“○”表示可得到的系统状态,用箭头“→”表示从一种状态向另一种状态的迁移。在箭头上要写上导致迁移的信号或事件的名字。
状态迁移图指明了作为特定事件的结果(状态)。在状态中包含可能执行的行为(活动或加工),因此当发生状态转移时,会伴随着相应的处理。
如果系统比较复杂,可以把状态迁移图分层表示。
在状态迁移图中,由一个状态和一个事件所决定的下一状态可能会有多个。实际会迁移到哪一个是由更详细的内部状态和更详细的事件信息来决定的。此时,可采用状态迁移图的一种变形,比如加进判断框和处理框等。
(2) Petri网
最初是用来表达异步系统的控制规则的图形表示法,后来Petri网在计算机科学中也得到广泛的应用。
Petri网简称PNG(Petri Net Graph),是一种有向图,包含四种基本元素,一组位置P(Place)、一组转换T(Transition)、输入函数I(Input)以及输出函数O(Output)。
§5.2 分析模型的结构
§5.2 分析模型的结构
位置P在图中用圆圈代表。
转换在图中用短直线表示。
转换的输入函数,用由位置指向转换的箭头表示。
转换的输出函数,用由转换指向位置的箭头表示。
Petri网位置中如果加了一个黑点,称之为标记(token)。标记在位置中的出现表明了处理要求的到来,表明系统或对象当前正处于此位置。
对于一个转换,当每个输入位置所拥有的标记数大于等于从该位置到转换的线数时,就允许转换。
Petri网中标记总数不是固定不变的
Petri网具有非确定性,即如果几个转换都达到了激发条件,则其中任意一个都可以被激发。
数据词典的作用是对于数据流图中出现的所有被命名的图形元素在数据词典中作为一个词条加以定义,使得每一个图形元素的名字都有一个确切的解释。
数据词典中所有的定义应是严密的、精确的,不可有半点含混并消除二义性。
(1) 数据词典的构成
(2) 数据词典的使用
可以通过数据名称方便地查问数据的定义;
可以按各种要求,随时列出各种表,以满足分析员的需要;
可以按描述内容(或定义)来查询数据的名称;
通过检查各个加工的逻辑功能,可以实现和检查在数据与程序之间的一致性和完整性;
在以后的设计与实现阶段,以至于到维护阶段,都需要参考数据词典进行设计、修改和查询。
(3) 数据结构的描述
Warnier图
Warnier图是表示数据层次结构的一种图形工具,它用树形结构来描绘数据结构。
在Warnier图中,用花括号“{”表示层次关系,在同一括号下,自上到下是顺序排列的数据项。
在有些数据项名字后面附加了圆括号,给出该数据项重复的次数。
Warnier图可以通过细化组合数据项进一步分解信息域。
(4) 加工逻辑说明
基本加工(原子加工):
数据流图最底层的加工;
对数据流图的每一个基本加工,必须有一个基本加工逻辑说明;
基本加工逻辑说明必须描述基本加工如何把输入数据流变换为输出数据流的加工规则;
加工逻辑说明必须描述实现加工的策略而不是实现加工的细节;
加工逻辑说明中包含的信息应是充足的,完备的,有用的,无冗余的。
用于加工逻辑说明的工具:
结构化英语
判定表
判定树
结构化英语 (Structured English)
结构化英语也称为PDL(过程设计语言),是一种介于自然语言和形式化语言之间的半形式化语言
结构化英语的词汇表由英语命令动词、数据词典中定义的名字、有限的自定义词和控制结构关键词 IF_THEN_ELSE、WHILE_DO、REPEAT_UNTIL、CASE_OF等组成
结构化英语基本控制结构有简单陈述句结构、判定结构和重复结构。
判定表(Decision Table)
在某些数据处理问题中,某数据流图的加工需要依赖于多个逻辑条件的取值,这时使用判定表来描述比较合适。
判定表由四个部分组成,双线分割开的四部分是:
判定树(Decision Tree)
判定树也是用来表达加工逻辑的一种工具。有时候它比判定表更直观。用它来描述加工,很容易为用户接受。
提纲
软件设计概述
软件概要设计的步骤
软件详细设计的步骤
软件设计模型
软件设计原则
软件设计基础
1. 软件设计的目标
软件设计的最基本目标就是回答“概括地描述系统如何实现用户所提出来的功能和性能等方面的需求?”这个问题。
软件设计的目标是根据软件需求分析的结果,设想并设计软件,即根据目标系统的逻辑模型确定目标系统的物理模型。包括软件体系结构设计、处理方式设计、数据结构和数据存储设计、界面和可靠性设计等方面。
软件设计也是后续开发步骤及软件维护工作的基础。如果没有设计,只能建立一个不稳定的系统结构。
2. 软件设计的过程
从工程管理角度来看,软件设计分两步完成。
首先做概要设计,将软件需求转化为数据结构和软件的系统结构,并建立接口。
然后是详细设计,即过程设计,通过对软件结构进行细化,得到各功能模块的详细数据结构和算法。
从技术观点来看,软件设计包含数据设计、系统结构设计和过程设计。
3. 软件设计在开发阶段中的重要性
软件设计是开发阶段中最重要的步骤,它是软件开发过程中质量得以保证的关键步骤。
软件设计又是将用户要求准确地转化成为最终的软件产品的唯一途径。
软件设计是后续开发步骤及软件维护工作的基础。
1. 制定设计规范
在进入软件开发阶段之初,首先应为软件开发组制定在设计时应该共同遵守的标准。包括:
2. 软件系统结构的总体设计
采用某种设计方法,将一个复杂的系统按功能划分成模块的层次结构
3. 处理方式设计
首先,需要确定为实现软件系统的功能需求所必需的算法,评估算法的性能。
其次,需要确定为满足软件系统的性能需求所必需的算法和模块间的控制方式(性能设计)。
4. 数据结构设计
确定软件涉及的文件系统的结构以及数据库的模式、子模式,进行数据完整性和安全性的设计。包括:
5. 可靠性设计
可靠性设计也称为质量设计。
软件可靠性简言之是指程序和文档中出现的错误较少。
软件经常需要修改和扩充,因此,开始设计软件的时候要考虑如何方便软件的修改和扩充的要求。
6. 界面设计
界面直观反映软件的系统功能,体现设计人员是否正确理解软件需求,同时也是快速软件开发的一个必需环节。
可以根据所采用的生命周期模型来确定实施界面设计的次序。
界面设计的方式、方法决定一个软件系统的易用性。
7. 编写概要设计阶段的文档
概要设计阶段完成时应编写以下文档:
8. 概要设计评审
详细设计过程需要完成的工作:
软件设计模型由静态结构和动态结构组成
软件设计模型取决于需求分析结果模型
软件设计模型通过软件设计活动得到:
软件的系统结构设计
软件的数据设计
软件的接口设计
软件的过程设计
软件的组件设计
软件的结构优化设计
1. 软件设计的一般原则
软件设计既是过程又是模型。
设计过程是一系列的迭代的设计活动,使设计人员能够描述目标系统的各个侧面。
设计模型首先描述目标系统的整体架构,然后逐步细化架构得到构造每个细节的指导原则,从而得到系统的一系列不同的视图。
良好的设计原则可为设计过程导航。
衡量设计过程的技术原则:
衡量设计模型的技术原则:
设计模型应该是一个分层结构。该结构:
使用可识别的设计模式搭建系统结构。
由具备良好设计特征的构件构成。
可以用演化的方式实现。
设计应当模块化。
设计应当包含数据、系统结构、接口和构件(模块)的清晰的视图。
设计应当根据将要实现的对象和数据模式导出合适的数据结构。
设计应当建立具有独立功能特征的构件。
设计应当建立能够降低模块与外部环境之间复杂连接的接口。
设计模型应当通过使用软件需求信息所驱动的可重复的方法导出
2. 模块化
(1) 模块的定义
模块又称构件,component,在传统的方法中指用一个名字就可调用的一段程序,或者可单独命名且可编址的软件组成部分。类似于高级语言中的过程、函数等。它一般具有如下三个基本属性:
(2) 模块的表示
必须按模块的外部特性与内部特性分别描述。
通常先确定外部特性(概要设计的任务),然后确定内部特性(详细设计的任务)。
(3) 良好的模块设计方法的标准
模块可分解性:可将系统按问题/子问题分解的原则分解成系统的模块层次结构;
模块可组装性:可利用已有的设计构件组装成新系统,不必一切从头开始;
模块可理解性:一个模块可不参考其他模块而被理解;
模块连续性:对软件需求的一些微小变更只导致对某个模块的修改而整个系统不用大动;
模块保护:将模块内出现异常情况的影响范围限制在模块之内。
(4)模块化方法的好处:
一方面,模块化设计降低了系统的复杂性,使得系统容易修改;
另一方面,推动了系统各个部分的并行开发,从而提高了软件的生产效率。
一个系统,即使它必须“整体”实现,不能做模块划分,也可以按照模块化概念进行设计。
(5)模块的化分
一个大而复杂的问题分解成一些独立的易于处理的小问题,解决起来就容易得多。
当进行问题分解的时候还必须注意,分解后的两个小问题之间应该保持相对的独立性,否则将会导致分解问题本身的工作量比不分解问题所花费的工作量要大得多。
C(P1+P2) > C(P1) + C(P2)的前提条件是P1和P2的集成很低,即要保证模块间的独立性。
3. 信息隐藏
如何分解一个软件才能得到最佳的模块组合?需要了解什么是“信息隐藏”。
David Parnas:每个模块的实现细节对于其它模块来说是隐蔽的。就是说,模块中所包含的信息(包括数据和过程)不允许其它不需要这些信息的模块使用。
信息隐藏使得在将来修改软件时偶然引入错误所造成的影响可以局限在一个或几个模块内部,不致波及到软件的其它部分。
4. 模块的独立性
模块独立性是指软件系统中每个模块只涉及软件要求的具体的子功能,而和软件系统中其它的模块的接口是简单的。
一般采用两个准则度量模块独立性,即单个模块的内聚和模块间的耦合。
(1) 内聚性(Cohesion)
内聚是模块功能强度(一个模块内部各个元素彼此结合的紧密程度)的度量。一个内聚程度高的模块(在理想情况下)应当只做一件事。一般模块的内聚性分为七种类型。
(2) 耦合性(Coupling)
耦合是模块之间的相对独立性(互相连接的紧密程度)的度量。它取决于各个模块之间接口的复杂程度、调用模块的方式以及哪些信息通过接口。
一般模块之间可能的连接方式有七种,构成耦合性的七种类型。
原则上讲,模块化设计的最终目标,是希望建立模块间耦合尽可能松散的系统。
由于模块间联系简单,发生在某一处的错误传播到整个系统的可能性很小。因此,模块间的耦合情况很大程度影响到系统的可维护性。
5. 降低模块间耦合度的方法
(1) 根据问题的特点选择适当的耦合类型
在模块间传递的信息有两种:一种是数据信息,一种是控制信息。传送数据的模块,其耦合程度比传送控制信息的模块耦合程度要低。
一方面,应当尽量减少和避免传送控制信息。
另一方面,也不要盲目地追求松散的耦合,耦合类型的选择,应当根据实际情况,全面权衡,综合地进行考虑。
松散的耦合类型有:非直接耦合、数据耦合、标记耦合。
(2) 降低模块接口的复杂性
模块接口的复杂性包括三个因素:一是传送信息的数量,即有关的公共数据与调用参数的数量;二是联系方式;三是传送信息的结构。
把调用序列中出现大量参数的被调用模块分解成更小的模块,使得每个小模块只完成一个任务,就可以减少模块接口的参数个数,降低模块接口的复杂性,从而降低模块间的耦合程度。
模块的联系方式(即调用方式)应当尽可能用call方式代替“直接引用”。
模块接口上传送的信息若能以标准的、直接的方式提供,则信息结构比较简单。若以非标准的、嵌套的方式提供,则信息结构比较复杂。
(3) 把模块的通信信息放在缓冲区中
缓冲区可以看作是一个先进先出的队列,它保持了通信流中元素的顺序。沿着通信路径而操作的缓冲区将减少模块间互相等待的时间。
在模块化设计时,如果能够把缓冲区作为每次通信流的媒介,那么一个模块执行的速度、频率等问题一般不影响其他模块的设计。
结构图是精确表达程序结构的图形表示方法。
它清楚地反映出程序中模块间的层次调用关系和联系:不仅严格地定义了各个模块的名字、功能和接口,而且还反映了设计思想。即它以特定的符号表示模块、模块间的调用关系和模块间信息的传递。
1. 什么是OOD
面向对象的设计就是在OOA模型基础上运用面向对象方法进行系统设计,目标是产生一个符合具体实现条件的面向对象设计(OOD)模型。
与实现条件有关的因素有:图形用户界面、硬件、操作系统、网络、数据库管理系统、编程语言和可复用的类库等。
OOA和OOD采用一致的表示法,使得从OOA到OOD不存在转换,只需要做必要的修改和调整,或补充某些细节,并增加几个与实现有关的相对独立的部分。
2. OOD主要工作
软件体系结构设计在用例实现方案设计之前进行,用户界面设计和其他两项工作之间无明显的先后次序关系
OOD的成果是以UML包图等表示的软件体系结构、以交互图和类图表示的用例实现、针对复杂对象的状态图和用以描述流程化处理过程的活动图等。
软件体系结构是描述某一特定应用领域中系统组织方式的惯用模式。
层次化的设计模型是面向对象方法基于软件体系结构风格的一种方案选择。它把软件设计组织成为类或组件的层次/集合,这些类或组件一起完成某一常见的目的,并使系统易于扩展和维护。
软件分层的好处:
软件分层的原则:
层应该是模块化的。应该能够重写某—层,或对整个层进行替换,只要接口保持不变,系统的其他部分应该不受影响。这将有助于系统易于扩展和维护,并增加软件的可移植性。
UML中用包图来描述层。常用的面向对象软件设计的五层软件分层结构如下:
1. 用户界面层
用户界面类实现了系统的主要用户界面元素
把用户界面类从业务领域类中分离出来,就可以使用我们选择的任何方式改变用户界面
用户界面层的实现要点:任何系统的用户界面能够以多种可能的形式出现,然而底层的业务逻辑却保持不变。
2. 控制器/处理层
控制器/处理类作为完成用例任务的责任承担者,用于协调、控制其他类共同完成用例规定的功能或行为
对于比较复杂的用例,控制器/处理类并不处理具体的任务细节,但是它应知道如何去分解任务、如何将子任务分派给其他的辅助类(如业务/领域类甚至其他控制器/处理类)、以及如何在辅助类之间进行消息传递和协调。
相似的用例可以共享同一个控制器类
简单的用例可以不设控制器类,直接在用户界面类中设置控制、协调功能
3. 业务/领域层
业务/领域类实现与业务领域相关的概念,源于领域模型,如“学生”或“试卷”。它着眼于业务对象数据方面的因素,加上单个对象相关的行为。
在OOA阶段关注的是问题域中概念的本质含义以及属性,在OOD阶段将会对这些概念增加操作,并进行必要的修改和调整,使之成为设计模型中业务/领域层中的类。
4. 持久化层
持久类把永久存储、检索、更新和删除对象的能力封装起来,使底层的存储技术不暴露出来。
持久层封装对永久存储介质的访问,但其本身并不是永久存储机制。
引入持久层的目的在于当数据存储机制或策略发生变化的时候,能减少维护工作。无论持久存储策略如何变化,业务/领域类都不会受影响,从而增加了应用程序的可维护性、可扩展性和可移植性。
5. 系统层
系统类为应用提供操作系统相关的功能,通过把特定于操作系统的特性包装起来,使软件与操作系统分离,这样增加了应用的可移植性。
系统类通过使用面向对象代码将操作系统提供的功能进行包装,封装了非面向对象功能。
系统类位于软件开发中的最低层,其他各层的类都可以向系统类发送消息,但是系统类只被允许向其他的系统类发送消息。在完成其工作的过程中,一般不需要知道关于业务逻辑和用户界面逻辑的任何信息。
在SRP中,将职责定义为“变化的原因”。
在构造对象时,应该将对象的不同职责分离至两个或多个类中,确保引起该类变化的原因只有一个,从而提高类的内聚度。
应用OCP原则设计出的模块具有两个主要的特征,它们是:
LSP做为一个检查工作来测试继承是否正确
如果没有LSP,类继承就会混乱;如果子类作为一个参数传递给方法,将会出现未知行为;
如果没有LSP,适用于基类的单元测试将不能成功用于测试子类;
在应用程序中所编写的大多数具体类都是不稳定的。我们不想直接依赖于这些不稳定的具体类。通过把它们隐藏在抽象接口的后面,可以隔离它们的不稳定性
如果一个具体类不太会改变,并且也不会创建其他类似的派生类,那么依赖于它并不会造成损害。
本质:如果一个服务器类为多个客户类提供不同的服务,那么,服务器类应该为每一个客户类创建特定的业务接口,而不要为所有客户类提供统一的业务接口,除非这些客户类请求的服务相同。
向一个客户提供超过客户要求的服务承诺,会给服务提供方带来不必要的维护负担
实现复用时应首先使用组合/聚合(黑盒复用),其次才考虑继承(白盒复用)。
在使用继承时,要严格遵循LSP原则。
如果两个类具有“has-a”关系则应使用组合/聚合,如果具有“is-a”关系则可使用继承。
符合下列条件的对象即为朋友:
提纲
结构化设计映射模型
系统功能结构图及数据流映射
数据设计和文件设计的原则
设计的后处理
详细设计
结构化需求分析模型中的每一个成份都提供了建立设计模型所需的信息。
根据数据、功能和行为模型来表示的软件需求,采用某种设计方法进行数据设计、系统结构设计和过程设计。
结构化设计方法是基于模块化、自顶向下细化、结构化程序设计等程序设计技术基础上发展起来的,它依据需求分析的结果“数据流图”推导出软件的系统功能结构图。
实施的要点是:
1. 系统功能结构图结构
(1) 系统结构图中的模块
传入模块 :从下属模块取得数据,经过某些处理,再将其传送给上级模块。
传出模块 :从上级模块获得数据,进行某些处理,再将其传送给下属模块。
变换模块 :即加工模块。它从上级模块取得数据,进行特定的处理,转换成其它形式,再传送回上级模块。大多数计算模块(原子模块)属于这一类。
协调模块 :对所有下属模块进行协调和管理的模块。 在系统的输入/输出部分或数据加工部分可以找到这样的模块。在一个好的系统结构图中,协调模块应在较高层出现。
(2) 变换型数据流与变换型系统结构
变换型数据处理问题的工作过程大致分为三步,即取得数据,变换数据和给出数据。
变换型系统结构对应于数据流中的取得数据、变换数据、给出数据,由输入、中心变换和输出等三部分组成。
(3) 事务型数据流与事务型系统结构图
事务型数据处理问题的工作机理是接受一项事务,根据事务处理的特点和性质,选择分派一个适当的处理单元,然后给出结果。选择分派任务的部分叫做事务处理中心,或分派部件。
2. 变换映射
变换映射是一组设计步骤,将具有变换流特征的数据流图映射为一个预定义的程序结构模版。
变换映射是体系结构设计的一种策略,运用变换映射方法建立初始的变换型系统结构图,然后对它做进一步的改进,最后得到系统的最终结构图。
中心变换: 多股数据流汇集的地方往往是系统的中心变换部分。
逻辑输入: 可以从数据流图上的物理输入开始,沿着数据流方向,一步一步向系统中间移动,一直到数据流不再被看作是系统的输入为止,则其前一个数据流就是系统的逻辑输入。
逻辑输出: 从物理输出端开始,沿着数据流反方向,一步一步地向系统中间移动,一直到数据流不再被看作是系统的输出为止,则其后一个数据流就是系统的逻辑输出。
3. 事务映射
事务映射也是从分析数据流图开始,自顶向下,逐步分解,建立有别于变换型的事务型系统结构图。
4. 变换—事务混合型的系统结构图
变换分析是软件系统结构设计的主要方法。一般,一个大型的软件系统是变换型结构和事务型结构的混合结构。所以,我们通常利用以变换分析为主,事务分析为辅的方式进行软件结构设计。
5. 改进系统功能结构图的启发式原则
(1) 模块功能的完善化
一个完整的模块应具有以下几个部分,且这几个部分应当看作是一个模块的有机组成部分,不应分离到其他模块中,否则将会增大模块间的耦合程度:
规定的功能部分;
出错处理部分。当模块不能完成规定的功能时,必须返回出错信息和标志,向它的调用者报告出现这种例外情况的原因;
如果需要返回一系列数据给它的调用者,当完成数据加工时应给它的调用者返回一个该模块执行是否正确结束的“标志”。
(2) 消除重复功能,改善软件结构
如果发现几个模块的功能有相似之处,可以加以改进。
完全相似:采取完全合并的方法,只需在数据类型的描述上和变量定义上加以修改就可以。
局部相似:找出两者之间的相同部分,重新定义一个独立的下一层模块,剩余的部分根据情况还可以与它的上级模块合并。
(3) 模块的作用范围应在控制范围之内
模块的控制范围包括它本身及其所有的从属模块。
模块的作用范围是指模块内一个判定的作用范围,凡是受这个判定影响的所有模块都属于这个判定的作用范围。
如果一个判定的作用范围包含在这个判定所在模块的控制范围之内,则这种结构是简单的,否则,它的结构是不简单的。
建议,所有受一个判定影响的模块应该都从属于该判定所在的模块,最好局限于做出判定的那个模块及其直接下属模块。
在设计过程中,当遇到作用范围不在控制范围之内,可应用如下办法把作用范围移到控制范围之内:
将判定所在模块合并到父模块中,使判定处于较高的层次;
将受到判定影响的模块下移到控制范围内;
将判定上移到层次中较高的位置。
(4) 尽可能减少高扇出结构
扇入:是指直接调用该模块的上级模块的个数。扇入大表示模块的复用程序高。
扇出:是指该模块直接调用的下级模块的个数。
如果一个模块的扇出数过大,就意味着该模块过分复杂,需要协调和控制过多的下属模块。应当适当增加中间层次的控制模块。
如果一个模块的扇入太大,而且它又不是公用模块,说明该模块可能具有多个功能。为此应当对其进一步分析并将其功能分解。
(5) 避免或减少使用病态联接
(6) 模块的大小要适中
体积过大的模块往往是由于分解不充分,且具有多个功能,因此需要对功能进一步分解,生成一些下级模块或同层模块。
模块体积较小时也可以考虑是否可能与调用它的上级模块合并。
通常规定其语句行数在50~100左右,最多不超过500行。
(7)设计功能可预测的模块,避免过分受限制的模块
一个功能可预测的模块,不论内部处理细节如何,但对相同的输入数据,总能产生同样的结果。
如果模块内部蕴藏有一些特殊的鲜为人知的功能时,这个模块就可能是不可预测的。
为了能够适应将来的变更,软件模块中局部数据结构的大小应当是可控制的,控制流的选择对于调用者来说,应当是可预测的,而与外界的接口应当是灵活的。
(8) 软件包应满足设计约束和可移植性
在选择模块设计的次序时,必须对一个模块的全部直接下属模块都设计完成之后,才能转向另一个模块的下层模块的设计;
在设计下层模块时,应考虑模块的耦合和内聚问题,以提高初始结构图的质量。
使用**“黑盒”技术**:在设计当前模块时,先把这个模块的所有下层模块定义成“黑盒”,在设计中利用它们时,暂时不考虑其内部结构和实现。在这一步定义好的“黑盒”,在下一步就可以对它们进行设计和加工。
如果出现了以下情况,就停止模块的功能分解:
1. 数据设计的原则
Pressman把数据设计的过程概括成以下两步:
Pressman提出了一组原则,用来定义和设计数据:
用于软件的系统化方法也适用于数据。
要确定所有的数据结构和在每种数据结构上施加的操作。
应当建立一个数据词典并用它来定义数据和软件的设计。
低层数据设计的决策应推迟到设计过程的后期进行。可以将逐步细化的方法用于数据设计。
数据结构的表示只限于那些必须直接使用该数据结构内数据的模块才能知道。
数据结构应当设计成为可复用的。
软件设计和程序设计语言应当支持抽象数据类型的定义和实现。
2. 文件设计的过程
文件设计指数据存储文件设计,其主要工作就是根据使用要求、处理方式、存储的信息量、数据的活动性,以及所能提供的设备条件等,来确定文件类别,选择文件媒体,决定文件组织方法,设计文件记录格式,并估算文件的容量。
主要分为两个阶段:
在经过变换映射和事务映射之后,还需要为所获得的系统功能结构图进行说明,作为**《概要设计说明书》**的一部分,包括以下内容:
1. 处理说明
处理说明是一个关于模块内部处理的清晰且无歧义的正确描述。这种说明描述了模块的主要处理任务、条件抉择和输入/输出。
2. 接口说明
给出一张表格,列出所有进入模块和从模块输出的数据,包括:
通过参数表传递的信息
对外界的输入/输出信息
访问全局数据区的信息
指出其下属的模块和上级模块。
3. 数据结构说明
数据结构的设计对每个模块的程序结构和过程细节都有深刻的影响,在软件结构确定之后,必须确定全局的和局部的数据结构。数据结构的描述可以用伪码(如PDL语言、类PASCAL语言)或Warnier图等形式表达。
4. 概要设计评审
评审中应着重评审软件需求是否得到满足,软件结构的质量、接口说明、数据结构说明、实现和测试的可行性和可维护性等。
5. 设计的优化(如果需要和可能的话)
简明的结构往往是精巧的和高效的:
优化要力争使模块的个数最少;
还应当寻求尽量简单的满足信息需求的数据结构。
对于有时间效率要求的软件,可以参考以下原则:
在不考虑时间运行要求进行优化的条件下构造并改进软件的结构。
在细节设计的过程中,挑出那些有可能占用过多时间的模块,并为这些模块精心设计出时间效率更高的过程(算法)。
用高级程序设计语言编写代码程序。
检测软件,分离出占用大量处理机资源的模块。
如果有必要,用依赖机器的语言(机器指令、汇编语言)重新设计或重新编码,以提高软件的效率。
从软件开发的工程化观点来看,在使用程序设计语言编制程序以前,需要对所采用算法的逻辑关系进行分析,设计出全部必要的过程细节,并给予清晰的表达,使之成为编码的依据,这就是详细设计的任务。
表达过程规格说明的工具叫做详细设计工具,它可以分为以下三类:
1. 程序流程图
程序流程图独立于任何一种程序设计语言,比较直观、清晰,易于学习掌握。
应对流程图所使用的符号做出严格的定义,不允许人们随心所欲地画出各种不规范的流程图。
为使用流程图描述结构化程序,必须限制流程图只能使用如下给出的五种基本控制结构。
任何复杂的程序流程图都应由这五种基本控制结构组合或嵌套而成。
2. N-S图
Nassi和Shneiderman 提出,也叫盒图
3. PAD图(Problem Analysis Diagram)
日本日立公司提出,由程序流程图演化来的,现在已为ISO认可。
PAD的执行顺序从最左主干线的上端的结点开始,自上而下依次执行。每遇到判断或循环,就自左而右进入下一层。
4. 判定表
判定表能清晰地表达复杂的条件组合与应做动作之间的对应关系。
判定表的优点是能够简洁,无二义性地描述所有的处理规则。但判定表表示的是静态逻辑,是在某种条件取值组合情况下可能的结果,它不能表达加工的顺序,也不能表达循环结构,因此判定表不能成为一种通用的设计工具。
5. PDL ( Program Design Language )
PDL是一种用于描述功能模块的算法设计和加工细节的语言。称为设计程序用语言。它是一种伪码。
具有以下特点:
提纲
软件实现
软件测试基础
软件测试方法与技术
软件测试过程
软件维护
从宏观上讲,软件实现包括详细设计、程序编码、单元测试和集成测试。
从微观上来讲,软件实现指程序编码和单元测试。
1. 软件实现的目标
软件实现的目标就是选择某种程序设计语言,将详细设计结果进行编码实现,并形成可执行的软件系统的过程。
2. 软件实现的任务
(1) 软件测试的定义(早期和狭义的定义)
(2) 软件测试的目的
设计测试的目标是想以最少的时间和人力系统地找出软件中潜在的各种错误和缺陷。
测试不能表明软件中不存在错误,它只能说明软件中存在错误。
(3) 软件测试的原则
应当尽早地和不断地进行软件测试。
测试用例应由测试输入数据和与之对应的预期输出结果这两部分组成。
程序员应避免测试自己的程序。
在设计测试用例时,应当包括合理的输入条件和不合理的输入条件。
充分注意测试中的群集现象。
严格执行测试计划,排除测试的随意性。
应当对每一个测试结果做全面检查。
妥善保存测试计划,测试用例,出错统计和最终分析报告,为维护提供方便。
软件的可测试性就是一个计算机程序能够被测试的容易程度。
在软件开发过程中,很多环节都能够影响软件的可测试性,例如需求分析的描述、设计架构、实现手段等
如果设计人员和程序员乐于完成一些对测试过程有帮助的工作,则可以极大提高软件的可测试性
软件测试并不等于程序测试,现代软件测试指为发现软件中存在的错误,对软件开发过程中形成的各项输出进行检查的过程。
测试应该贯穿于软件开发的整个期间,需求分析规格说明、概要设计说明、详细设计说明、单元代码、集成的系统以及其他输出文档,都应该成为测试的对象。
广义的软件测试包含三类具体活动:
测试过程需要三类输入:
6. 软件测试与软件开发各阶段的关系
软件开发过程是一个自顶向下,逐步细化的过程,而测试过程则是依相反的顺序安排的自底向上,逐步集成的过程。低一级测试为上一级测试准备条件。
1. 测试技术分类
常用的测试分类和测试用例设计方法
(1) 黑盒测试
黑盒测试又叫做功能测试、数据驱动测试或基于规格说明的测试,指在不考虑程序内部结构和内部特征的情况下,根据软件产品的功能设计规格说明,在计算机上进行测试,以证实每个实现了的功能是否符合要求。
黑盒测试主要是为了发现以下几类错误:
(2) 白盒测试
白盒测试又称为结构测试、逻辑驱动测试或基于程序的测试,指根据软件产品的内部工作过程,在计算机上进行测试,以证实每种内部操作是否符合设计规格要求,所有内部成分是否已经过检查。
白盒测试方法主要对程序模块进行如下检查:
无论黑盒测试还是白盒测试,如果实行穷举测试,由于工作量过大,实施起来是不现实的,需要精心地挑选少量的测试数据,使得采用这些测试数据能够达到最佳的测试效果。
2. 白盒测试技术
(1) 逻辑覆盖
逻辑覆盖是以程序内部的逻辑结构为基础的设计测试用例的一种白盒测试技术。
逻辑覆盖可分为:语句覆盖、判定覆盖、条件覆盖、判定-条件覆盖、条件组合覆盖及路径覆盖。
语句覆盖(点覆盖):设计若干个测试用例,运行被测程序,使得每一可执行语句至少执行一次。
A=2,B=0,X=4,即达到了语句覆盖
判定覆盖(分支覆盖):设计若干个测试用例,运行被测程序,使得程序中每个判断的取真分支和取假分支至少经历一次。
A=3,B=0 ,X=3 可覆盖a、c、d分支
A=2,B=1 ,X=1 可覆盖a、b、e分支
条件覆盖:设计若干个测试用例,运行被测程序,使得程序中每个判断的每个条件的可能取值至少执行一次。
A=1,B=0 ,X=3,满足条件 T1(假),T2 (真),T3 (假) , T4 (真) ,可覆盖a、b、e分支
A=2,B=1 ,X=1,满足条件 T1 (真) ,T2 (假) ,T3 (真) , T4 (假) ,还是覆盖a、b、e分支
判定-条件覆盖:设计足够的测试用例,使得判断中每个条件的所有可能取值至少执行一次,同时每个判断本身的所有可能判断结果至少执行一次。
A=2,B=0 ,X=4,满足条件 T1(真),T2 (真),T3 (真) ,T4 (真) ,可覆盖a、c、e分支
A=1,B=1 ,X=1,满足条件 T1(假),T2 (假),T3 (假) ,T4 (假) ,覆盖a、b、d分支
多重条件覆盖:设计足够的测试用例,运行被测程序,使得每个判断的所有可能的条件取值组合至少执行一次。
A=2,B=0 ,X=4,满足条件 T1(真),T2(真),T3 (真) , T4 (真) ,覆盖a、c、e分支
A=2,B=1 ,X=1,满足条件 T1(真),T2(假),T3 (真) , T4 (假) ,覆盖a、b、e分支
A=1,B=0 ,X=2,满足条件 T1(假),T2(真),T3 (假) , T4 (真) ,覆盖a、b、d分支
A=1,B=1 ,X=1,满足条件 T1(假),T2(假),T3 (假) , T4 (假) ,覆盖a、b、d分支
路径测试:设计足够的测试用例,覆盖程序中所有可能的路径, 这是最强的覆盖准则。
A=2,B=0 ,X=4,满足条件 T1(真),T2 (真),T3 (真) , T4 (真) ,覆盖a、c、e分支
A=3,B=0 ,X=1,满足条件 T1(真),T2 (真),T3 (假) , T4 (假) ,覆盖a、c、d分支
A=1,B=1 ,X=2,满足条件 T1(假),T2 (假),T3 (假) , T4 (真) ,覆盖a、b、e分支
A=1,B=1 ,X=1,满足条件 T1(假),T2 (假),T3 (假) , T4 (假) ,覆盖a、b、d分支
(2) 基本路径测试
真正做到完全路径覆盖是很困难的,必须把覆盖路径数目压缩到一定限度。如果把覆盖的路径数压缩到一定限度内,例如,程序中的循环体只执行零次和一次,就称为基本路径测试 。
设计出的测试用例要保证在测试中,程序的每一个可执行语句至少要执行一次。
基本路径测试步骤:
步骤1:导出程序的控制流图
控制流图是描述程序控制流的一种图示方法。基本控制构造的图形符号如下所示:
边和结点圈定的区域叫做区域,当对区域计数时,图形外的区域也应记为一个区域。
如果判定中的条件表达式是复合条件时,即条件表达式是由一个或多个逻辑运算符(OR,AND,NAND,NOR)连接的逻辑表达式,则需要改复合条件的判定为一系列只有单个条件的嵌套的判定。
步骤2:计算程序环路复杂性
通常环路复杂性可用以下三种方法求得。
上图所示控制流图环路复杂度为4,因为:
控制流图有4个区域
控制流图边数和点数满足 E-N+2=11-9+2=4
控制流图判定结点数为3, 复杂度=3+1=4
步骤3:确定基本(独立)路径集
程序的环路复杂性给出了程序基本路径集合中的独立路径条数,这是确保程序中每个可执行语句至少执行一次所必需的测试用例数目的上界。
基本(独立)路径:指程序的控制流图中从入口到出口的路径,该路径包括一组以前没有处理的语句或条件。
基本路径集不是唯一的,对于给定的控制流图,可以得到不同的基本路径集。
步骤4:设计测试用例
根据前面所得到的基本路径集,设计测试用例,覆盖全部基本路径。
只要设计出的测试用例能够确保这些基本路径的执行,就可以使得程序中的每个可执行语句至少执行一次,每个条件的取真和取假分支也能得到测试。
(3) 控制结构测试
基本路径测试技术是控制结构测试技术之一。尽管基本路径测试简单高效,但是其并不充分。
控制结构测试中的其它测试技术:
3. 黑盒测试技术
(1) 等价类划分
**这一方法完全不考虑程序的内部结构,只依据程序的规格说明来设计测试用例。**黑盒测试中,用所有可以输入的数据来测试程序是不可能的,只可能从全部可供输入的数据中选择一个子集进行测试。因此,该方法是把所有可能的输入数据划分为若干部分,从每一部分中选取少数有代表性的数据作为测试用例。
**划分等价类:**所谓等价类是指某个输入域的子集合,在该子集合中,各个输入数据对于揭露程序中的错误都是等效的。
等价类的划分有两种不同的情况:
划分等价类的原则:
按区间划分
按数值集合划分
输入条件是一个布尔量的划分
按数值划分
按限制条件或规则划分
如果已划分的等价类中各元素在程序中的处理方式不同,则应将此等价类进一步划分成更小的等价类
(2) 边界值分析
人们从长期的测试工作经验得知,大量的错误是发生在输入或输出范围的边界上,而不是在输入范围的内部。因此针对各种边界情况设计测试用例,可以查出更多的错误。
这里所说的边界是指,相当于输入等价类和输出等价类而言,稍高于其边界值及稍低于其边界值的一些特定情况。
边界值分析方法是最有效的黑盒测试方法,但当边界情况很复杂的时候,要找出适当的测试用例还需针对问题的输入域、输出域边界,耐心细致地逐个考虑。
边界值分析法选取测试用例的原则:
(3)错误推测法
错误推测法指的是人们依靠经验和直觉推测程序中可能存在的各种错误,从而有针对性地编写检查这些错误的例子的测试方法。
错误推测法的基本想法是:列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据它们选择测试用例。
(4)因果图
如果在测试时必须考虑输入条件的各种组合,可能的组合数将是天文数字。因此必须考虑使用一种适合于描述对于多种条件的组合,相应产生多个动作的形式来考虑设计测试用例,这就需要利用因果图。
因果图方法最终生成的就是判定表。它适合于检查程序输入条件的各种组合情况。
4. 测试方法选择的综合策略
在任何情况下都必须使用边界值分析方法。经验表明用这种方法设计出测试用例发现程序错误的能力最强
必要时用等价类划分方法补充一些测试用例
用错误推测法再追加一些测试用例
对照程序逻辑,检查已设计出的测试用例的逻辑覆盖程度。如果没有达到要求的覆盖标准,应当再补充足够的测试用例
如果程序的功能说明中含有输入条件的组合情况,则一开始就可选用因果图法
软件测试过程包括单元测试、集成测试、确认测试、系统测试和验收测试
1. 单元测试
单元测试又称为模块测试,是针对程序模块进行正确性检验的测试。主要采用白盒测试为主、黑盒测试为辅的测试方法
单元测试的步骤
单元测试在编码阶段进行,是编码步骤的附属部分。源程序代码编制完成,经过评审和验证,确认没有语法错误之后,就开始进行单元测试的测试用例设计
模块并不是一个独立的程序,在考虑测试模块时,同时要考虑它和外界的联系,用一些辅助模块去模拟与被测模块相联系的其它模块。
这些辅助模块分为两种:
驱动模块(driver):相当于被测模块的主程序。它接收测试数据,把这些数据传送给被测模块,最后输出实测结果。
桩模块(stub):也叫做存根模块,用以代替被测模块调用的子模块。
2. 集成测试
在单元测试的基础上,需要将所有模块按照设计要求组装成为系统。
把模块组装成为系统的方式有两种:
增量式集成方式的几种类型:
3. 确认测试
确认测试又称有效性测试,它的任务是验证软件的有效性,即验证软件的功能和性能及其它特性是否与用户的要求一致。
确认测试步骤:首先进行有效性测试,其次进行软件配置复审,在通过了专家鉴定之后,才能成为可交付的软件。
有效性测试(功能测试)
有效性测试是在模拟的环境(可能就是开发的环境)下,运用黑盒测试的方法,验证被测软件是否满足需求规格说明书列出的需求
软件配置复查: 软件配置复查的目的是保证软件配置的所有成分都齐全,各方面的质量都符合要求,具有维护阶段所必需的细节,而且已经编排好分类的目录
4. 系统测试
所谓系统测试,是将通过确认测试的软件,作为整个基于计算机系统的一个元素,与计算机硬件、外设、某些支持软件、数据和人员等其它系统元素结合在一起,在实际运行(使用)环境下,对计算机系统进行一系列的组装测试和确认测试。
系统测试包括:
5. 验收测试
系统试运行一段时间后,各方面均已满足需求,可以进行验收,验收前展开的最后测试叫做验收测试。
1. 软件维护的定义
所谓软件维护就是在软件已经交付使用之后,为了改正错误或满足新的需要而修改软件的过程,即在软件运行∕维护阶段对软件产品所进行的一切改动。
进行软件维护的原因:
2. 软件维护的分类