【软件工程】山东大学软件工程复习提纲

涵盖所有考点,复习绝对高效,点赞+留邮箱获取pdf版本

软件工程复习提纲

本提纲可以完全摘抄,考试命中率100%,先上考试带的A4纸:
请添加图片描述
在这里插入图片描述

1. 名词解释题

1. 软件工程三要素

  • 方法:为软件开发提供了“如何做 ”的技术,如项目计划与估算、软件系统需求分析、数据结构、系统总体结构的设计等;
  • 工具:为软件工程方法提供了自动的或半自动的软件支撑环境,如把软件工具集成起来,建立起称之为计算机辅助软件工程 (CASE) 的软件开发支撑系统。CASE 将各种软件工具、开发机器和一个存放开发过程信息的工程数据库组合起来形成一个软件工程环境;
  • 过程:将软件工程的方法和工具综合起来以达到合理、及时地进行计算机软件开发的目的,它定义了:方法使用的顺序,要求交付的文档资料,为保证质量和适应变化所需要的管理,软件开发各个阶段完成的里程碑。

2. 软件工程原则

  • 抽象:抽取事物最基本的特性和行为,忽略非基本的细节,采用分层次抽象,自顶向下、逐层细化的办法控制软件开发过程的复杂性;
  • 信息隐蔽:将模块设计成“黑箱”,实现的细节隐藏在模块内部,不让模块的使用者直接访问。这就是信息封装,使用与实现分离的原则,使用者只能通过模块接口访问模块中封装的数据;
  • 模块化:模块是程序中逻辑上相对独立的成分,是独立的编程单位,应有良好的接口定义。如C语言程序中的函数过程,C++语言程序中的类。模块化有助于信息隐蔽和抽象,有助于表示复杂的系统;
  • 确定性:软件开发过程中所有概念的表达应是确定的、无歧义性的、规范的。这有助于人们之间在交流时不会产生误解、遗漏,保证整个开发工作协调一致;
  • 一致性:整个软件系统(包括程序、文档和数据)的各个模块应使用一致的概念、符号和术语。程序内部接口应保持一致。软件和硬件、操作系统的接口应保持一致。系统规格说明与系统行为应保持一致。用于形式化规格说明的公理系统应保持一致;
  • 完备性:软件系统不丢失任何重要成分,可以完全实现系统所要求功能的程度。为了保证系统的完备性,在软件开发和运行过程中需要严格的技术评审;
  • 可验证性:开发大型的软件系统需要对系统自顶向下、逐层分解。系统分解应遵循系统易于检查、测试、评审的原则,以确保系统的正确性。

3. 软件生命周期

image-20220618225306207

4. 软件开发过程

按照项目的进度、成本和质量限制,开发和维护满足用户需求的软件所必需的一组有序的软件开发活动集合。

5. 统一开发过程

不仅仅是一个简单的软件过程,而是一个通用的过程框架,可用于不同类型的应用系统,它是基于构件的,所构造的软件系统是由软件构件通过明确定义的接口相互链接所建造起来的。并且它使用 UML 语言来制定系统的所有蓝图。

6. 软件过程模型

软件过程模型是软件开发全过程中软件开发活动以及它们之间关系的结构框架,用于指导软件的开发。常用的软件过程模型有:

瀑布模型

瀑布模型将开发阶段描述为从一个阶段瀑布般地转换到另一个阶段,一个阶段必须在另一个阶段开始之前完成,每一个阶段都伴随着定义明确的里程碑和可交付产品。顺序为:

  • 需求分析:软件需求规格说明书;
  • 系统设计:软件系统设计文档;
  • 程序设计:软件功能模块算法和数据描述文档;
  • 编码:源程序和注释;
  • 单元和集成测试:单元和集成测试报告;
  • 系统测试:系统测试报告;
  • 验收测试:验收测试报告;
  • 运行和维护:维护报告;

优点:中间产品和接口的定义明确,开发人员可以专注于完成每一个小的阶段,测试和审核流程完备,系统整体质量高;

缺点:缺乏灵活性,速度慢,不能反映实际的代码开发方式;对开发人员的要求很高,必须在项目开始前说明全部需求;最终产品直到最后才出现,而软件客户无法在早期直到软件原型。

适用场合:①有稳定的产品定义和需求分析;②容易理解但很复杂的项目;③质量需求高于成本需求和进度需求;④开发团队的技术力量较弱或缺乏经验。

原型模型

开发人员在与用户进行需求分析时,以较小代价快速建立一个能反映用户需求的原型系统,综合用户的意见对原型系统进行完善,然后再由用户评价,重复这一过程直到用户满意,再开始正式设计。

优点:符合人们认识事物的规律,缩短了用户和开发人员之间的距离,确保设计的软件是符合用户要求的,缩短了整体开发周期;

缺点:难以模拟大型系统和批处理系统,文档容易被忽略,项目难以清晰地规划和管理。

适用场合:①不能预先确切定义需求的软件系统;②开发人员不能很好地交流的情况。

增量模型

先开发系统的主要功能,然后,随着时间推进,不断增加新的次要功能,最终开发出一个完整的软件产品。

优点:①有利于增加客户对系统的信心;②降低系统失败风险;提高系统可靠性,稳定性和可维护性;

缺点:①增量粒度难以选择;②每个增量必须依赖之前的增量,耦合度增加;③容易退化为边做边改,失去软件过程的整体性。

适用场合:①进行已有产品升级或新版本开发;②完成期限严格要求的产品;③已有原型系统;④开发人员整体水平有限,可以边学习边开发。

螺旋模型

螺旋模型的基本做法是在“瀑布模型”的每⼀个开发阶段前,引入⼀个非常严格的风险识别、风险分析和风险控制。它把软件项目分解成⼀个个小项目,每个小项目都标识⼀个或多个主要风险,直到所有的主要风险因素都被确定。

四象限:螺旋模型每次迭代有四个任务,依次是:计划、目标/可选方案、风险评估、 开发与测试;

四循环:螺旋模型共有四次迭代,依次是:操作概念、软件需求、软件设计、开发与测试。

优点:①支持需求的动态变化,具有良好的扩展性;②易于用户和开发人员共同理解需求,还可作为继续开发的基础;③强调风险分析,使软件最终的安全性和稳定性都大大提升;

缺点:①需要开发人员有丰富的风险评估知识;②开发周期长,迭代次数多,可能延迟项目验收时间。

敏捷开发模型

为缓和传统开发模型固守成规的缺点,提出了敏捷开发模型,它以用户的需求进化为核心,采用迭代、循序渐进的方法进行软件开发,总体目标是:尽早地、持续性地交付有价值的软件,使客户满意。

敏捷宣言:

  • 个人和交互 > 过程和工具:面对面沟通而不是文档沟通;
  • 软件的生产 > 文档的编写:成功的指标是软件正确工作的程度;
  • 与客户合作 > 合同和谈判:以客户的需求为主导核心;
  • 对变化的反应 > 遵循计划:不可能在开始时就能预测到所有变化。

极限编程:

是典型的敏捷开发方法,包含 4 个理念:①交流:客户与开发人员之间持续地交换看法;②简单性:选择简单的实现来满足客户的需要;③勇气:尽早和经常性地做出交付的承诺;④反馈:各种反馈活动应该贯穿整个过程。

敏捷管理实践:

  • 每日站立会议:每日工作前,由 Scrum Master 带领团队成员准时例行沟通项目进展和解决方案;
  • 可视化管理:将项目状态通过物理实体实时展示,让团队所有成员直观地获取当前项目进展信息;
  • 用户故事:站在用户的视角,用简短的语句描述用户需求;
  • 结对编程:使用一个键盘,两个结成对的程序员,一个负责敲入代码,而另外一个实时检视每一行敲入的代码;
  • 测试驱动开发:在编写任何代码之前,首先编写定义代码功能的测试用例,编写的代码要通过用例;
  • 持续集成:团队的成员经常集成他们的工作,通常每人每天至少集成一次,大幅度缩短反馈周期;

优点:①采用简单计划策略,不需要长期计划和复杂模型,开发周期短;②在全过程采用迭代增量开发、反馈修正和反复测试的方法,能够适应用户经常变化的需求;③注重市场快速反应能力,客户前期满意度高;

缺点:①注重人员的沟通,忽略文档的重要性,若项目人员流动大太,给维护带来不少难度;②对编码人员的经验要求高,若项目存在新手比较多时,老员工比较累。

适用范围:①项目经常发生变更;②高风险的项目实施;③开发人员水平高,可以参与决策;④有优秀的敏捷顾问。

7. 跟踪项目进展

  • 项目进度:项目进度是对特定项目的软件开发周期的刻画。包括对项目阶段、步骤、活动的分解,对各个离散活动的交互关系的描述,以及对各个活动完成时间及整个项目完成时间的初步估算。

  • 活动:项目的一部分,一般占用项目进度计划的一段时间;

  • 里程碑:特定的时间节点,标志着活动的结束,通常伴随着提交产物;

  • WBS:Work Breakdown Structure,项⽬按⼀定的原则分解,项⽬分解成任务,任务再分解成⼀项项⼯作,再把⼀项项⼯作分配到每个⼈的⽇常活动中,直到分解不下去为⽌,树形表示;

  • WBS 分解方法:①类比法:参考类似的项目方法或模板;②自顶向下法;③自底向上法;

  • 活动图:描述活动之间的依赖关系,图中结点是项目里程碑,线表示活动;

  • AOE 网络:有向图 G 中,若用顶点代表事件,有向边表示活动,有向边上的权值表示一项活动持续的时间,则称图 GAOE 网络;

    • 关键路径:从源点到汇点的最长路径;
    • 关键活动:关键路径上的活动。或对整个工程的最短完成时间有影响的活动。即如它不能按期完成就会影响整个工程。;
  • 项目组织:

    • 民主制程序员组:小组成员完全平等,互相交流以做出决策,适用规模较小的组织;
    • 主程序员组:每个小组成员必须经常与主程序员交流,而不必与其他小组成员交流;
    • 现代程序员组:结合民主制程序员组和主程序员组的优点,“主程序员”由两人担任,技术负责人负责小组的技术活动,行政负责人负责所有非技术的管理决策。

8. 软件规模评估方法

①代码行分析法;②功能点分析法;③专家判断技术;④标准回归技术;⑤神经网络技术;⑥贝叶斯分析技术;⑦类比法。

9. 软件风险

使软件项目的实施受到影响和损失、甚至导致失败的、可能会发生的事件。

  • 风险影响:发生风险后会造成的损失;
  • 风险概率:发生风险的概率;
  • 风险暴露:= 风险影响 × 风险概率,量化风险所造成的影响;
  • 降低风险的三种策略:
    • 避免风险:通过改变软件的性能或功能需求;
    • 转移风险:把风险分配到其它系统中,或购买保险;
    • 控制风险:预先假设风险会发生,接受并采取措施提前控制;
  • 风险杠杆:= (降低前的风险暴露 - 降低后的风险暴露) / 降低风险的成本,如果杠杆值不够高,不足以证明采取措施的理由,那么可以采取其它措施降低风险。

10. CASE

计算机辅助软件工程,用来支持管理系统开发的、由各种计算机辅助软件和工具组成的大型综合性软件开发环境,如图工具、流程建模工具、文档编写工具、集成测试工具的集合。

11. 需求

需求是对期望的行为的表达,是用户需解决某一问题或达到某一目标所需的软件功能;

  • 功能需求:描述系统预期提供的功能或服务;
  • 非功能需求:指那些不直接与系统具体功能相关的一类需求,如并发性,响应时间,可靠性;
  • 领域需求:源于系统的应用领域需求,如敏感信息下载后要及时删除;

12. OCL(对象约束语言)

Object Constraint Language,是一个形式化语言,和 ER 图或 UML 紧密结合在一起,用于表示类图中的不变量、前置条件、后置条件、转移条件等,帮助类图表示地更清晰。

13. 原型化需求

开发人员快速构建一个原型以确保是否符合用户需求,在需求确定后再开始正式开发;

  • 抛弃型原型:编写快速但不考虑质量的原型,可以迅速抓住问题的核心,一旦确定需求就抛弃掉它,速度快但可迭代性差;
  • 演化型原型:编写的原型不仅要抓住问题核心,还要迭代成为最终产品,速度慢但可迭代性高;
  • 快速原型化:上述两种方法统称为快速原型化。

14. 设计过程模型:

image-20220619193358160

软件系统设计是一个迭代的过程,最终结果是软件体系结构文档(SAD)。

15. 分解

自顶向下地分解软件涉及的每一个模块,帮助开发者更好地把握软件设计流程,几个流行的分解方案为:

  • 面向功能的分解:把功能或需求分解成模块;
  • 面向特征的分解:也是把功能或需求分解成模块,但是为模块制定了细化的特征;
  • 面向数据的分解:将数据分解成模块;
  • 面向进程的分解:将系统分解成一系列并发的进程;
  • 面向事件的分解:将系统处理的事件分解成模块;
  • 面向对象的分解:将对象分解成模块;

16. 模块化的

当系统的每个活动都仅由对应的软件单元实现,并且每个软件单元的输入和输出都已经明确地被定义时,设计才可以说是模块化的;

17. 定义明确的

如果一个软件单元的接口能够准确无误地指定该单元的外部可见行为,则称该软件单元是定义明确的;

18. 视图

将软件分解形成为构件后,将它们合适地排列以展示各个构件之间的交互和系统整体的架构的一种表示形式;体系结构视图包含以下几种:

  • 分解视图:例如 UML 用例图,是层次化的分解,使用了多种模型,每个模块是可编程的;
  • 依赖视图:展示了软件单元之间的依赖关系,帮助确定哪些单元是独立的,哪些是耦合的;
  • 泛化视图:展示了一个软件单元是否被另一个单元所泛化,在设计抽象单元时经常使用;
  • 执行视图:传统的 方框->箭头 视图,展示了系统运行时的结构,每个构件都是执行实体;
  • 实现视图:在代码单元和源文件之间建立映射,有助于管理源代码;
  • 部署视图:在运行实体和 IT 资源之间建立映射,帮助分析系统的底层设计;
  • 工作分配视图:每个构件是分配给团队成员的任务,有助于项目管理;

19. 体系结构风格

体系结构风格反映了领域中众多系统所共有的结构和语义特性,并指导如何将各个模块和子系统有效地组织成一个完整的系统。

经典的体系结构风格:

  • 管道/过滤器:将数据输入到过滤器中得到输出数据,通过管道将数据从一个过滤器中传输到下一个过滤器;

    • 优点:
      • 各个模块相对独立,在输入和输出定义清楚后,便于模块化开发和测试;
      • 支持一些特定的分析,例如吞吐量计算和死锁检测;
      • 并发性高,当一个模块的吞吐量达到瓶颈后,可以新增一个同样的构建分担压力;
    • 缺点:
      • 交互式处理能力弱;
      • 具体实现比较复杂,例如要考虑数据流同步问题和数据加解密问题;
  • 层次结构:整个系统被组织成一个分层结构,每一层为上层提供服务,并作为下一层的客户。

    image-20220619202339477

    • 优点:

      • 层次结构风格支持系统设计过程中的逐级抽象;
      • 基于层次结构风格的系统具有较好的可扩展性;
      • 层次结构风格支持软件复用;
    • 缺点:

      • 并不是每个系统都可以很容易地划分为分层的模式;
      • 很难找到一个合适的、正确的层次抽象方法;
  • C/S 风格:C/S 体系结构有三个主要组成部分:客户机、服务器和专用的网络;

    • 优点:①界面丰富,可操作性高;②安全性高;③响应速度快;
    • 缺点:①适用范围窄;②用户群固定;③维护成本高;④需安装专门的软件;
  • B/S 风格:B/S体系结构有三个主要组成部分:浏览器、 Web 服务器、数据库服务器;

    • 优点:①维护和升级方式简单;②交互性强;③对客户机的配置要求低;
    • 缺点:①在速度和安全性上需要花费巨大的成本;②需要刷新页面;③通信开销大;

20. 设计原则

设计原则是指把系统功能和行为分解成模块的指导方针。

六种重要的设计原则:

  • 模块化:把系统中各不相关的部分进行分离的原则,以便于各部分能够独立研究,也称为关注点分离,每个模块都有自己唯一的目的,并且相对独立于其它模块。

    使用两个概念来度量模块的独立程度:耦合度和内聚度;

    • 耦合度:两个模块之间存在着很强的依赖关系称为紧密耦合,两个模块之间存在较少依赖关系称为松散耦合,模块之间没有任何依赖关系称为无耦合。耦合越松散,模块之间的联系就越小,模块的独立性就越强。

      常见的耦合类型:

      • 非直接耦合:两个模块都能独立地工作而不需要另一个模块的存在,耦合度最低;
      • 数据耦合:两个模块彼此之间通过传参交换数据,称为数据耦合;
      • 标记耦合:两个模块之间传参交换复杂的数据结构变量,如数组、类名;
      • 控制耦合:两个模块之间传递的信息是控制信息,表现在循环和条件判断语句中;
      • 公共耦合:各模块访问同一个公共数据,如共享内存区,只读的公共耦合是松散耦合,读写的公共耦合是紧密耦合;
      • 内容耦合:耦合度最高,①一个模块直接访问另一个模块的内部数据;②一个模块通过分支进入了另一个模块;③模块之间的代码发送重叠;

      尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,完全不采用内容耦合。

    • 内聚度:内聚是衡量一个模块内部各个元素彼此结合的紧密程度,一个模块内聚程度越高,说明该模块内部各元素之间的关联也就越强。

      内聚度由低到高为:

      • 偶然内聚:只是因为巧合或方便的原因,不相关的功能、进程或数据处于同一个模块中,是最差的一种内聚,模块不易理解,不易维护,不易重用;
      • 逻辑内聚:模块中的各个部分只通过代码的逻辑结构相关联,但实际功能没有关联;
      • 时间内聚:各个元素必须在同一时间内执行(比如系统初始化),优点是实现简单,缺点是模块结合了许多无关的任务,一旦模块失败,难以定位错误位置;
      • 过程内聚:元素之间有顺序关系,调用前面元素之后,紧接着调用后面的,例如必须先进行词法分析,才能进行语法分析;
      • 通信内聚:模块各功能部分都操作同一输入 ,或产生同一输出,例如语法分析和语义分析都操作词法分析的结果,都输出中间代码;
      • 顺序内聚:模块内的处理元素和同一个功能密切相关,而且这些处理必须顺序执行,前一元素的输出就是下一元素的输入,例如将词法分析–>语法分析–>语义分析和中间代码生成整合成一个模块;顺序内聚模块中的各个部分在功能和执行顺序上都密切相关,构成个不可分割的整体,因此内聚程度高且易于理解;
      • 功能内聚:一个模块内所有处理元素仅为完成功能而协同工作,紧密联系,不可分割,且没有副作用,则称为功能内聚。功能内聚是最高程度的内聚。在设计时应尽可能使模块到达功能内聚这一级。
  • 接口:接口定义了模块能正确工作的环境,以及格式化的输入输出,隐藏了模块实现细节;

  • 信息隐藏:对使用模块的用户隐藏模块实现相关的信息,例如用户只需要知道函数能够排序,而不需管其底层是冒泡排序还是快速排序;

  • 增量式开发:将每个模块看作一个增量组件,并按优先级分批次分析、设计、开发、测试和交付增量组件;

  • 抽象:忽略细节,提炼出模块之间的共性,或建设整体视图,或设计接口类;

  • 通用性:开发软件时,尽量使其成为通用的软件,以便在将来将其复用到另一系统中;

21. 面向对象三大原则

封装、继承和多态;

22. 面向对象设计原则

  • 单一职责原则:一个类只负责一个职责,这样可以增加模块的可复用性,系统整体高内聚、低耦合;

  • 开闭原则:一个软件实体应当对扩展开放,对修改关闭,即在不改变本身代码的情况下其行为能扩展,面临新的需求时,不要更改已有的代码,而是在其基础上进行扩展;

    • 抽象化是开闭原则的关键;
  • 里氏代换原则:一个软件如果使用的是一个父类的话,那么一定适用于其子类,而察觉不出父类对象和子类对象的区别。也即是说,在软件里面,把父类替换成它的子类,程序的行为不会有变化,简单地说,子类型必须能够替换掉它们的父类型;

    • 反过来则不成立,如果一个软件实体使用的是一个子类的话,那么它不一定能够使用基类;
    • 在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象;
    • 子类可以扩展父类的方法,但是不能修改父类的方法,本质上也是对开闭原则的一种完善;
  • 依赖倒转原则:高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象。

    • 要针对接口编程,不要针对实现编程;
    • 常用实现方式之一是在代码中使用抽象类,而将具体类放在配置文件中;
    • 以抽象方式耦合是依赖倒转原则的关键;

    例如,下图1未实现依赖倒转原则,图2实现了依赖倒转原则:

    image-20220620014412150

    image-20220620014417712

  • 合成复用原则:尽量使用对象组合,而不是继承来达到复用的目的;

    • 复用时要尽量使用 组合/聚合 关系,少用继承;
    • 继承复用称为白箱复用,因为父类对子类是完全透明的,组合/聚合 复用是黑箱复用;

    例如,下图1是继承复用,冗余项多且庞杂,图2是聚合复用,简介且易维护:

    在这里插入图片描述

    在这里插入图片描述

  • 迪米特法则:又称为最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用,这样,当一个模块修改时,就会尽量少的影响其他的模块,扩展会相对容易;

    • 可以降低类之间的耦合度,从而允许它们独立地被开发、优化、使用和修改;
    • 迪米特法则的主要用途在于控制信息的过载,例如应尽量创造松耦合的类,尽量降低对类成员变量和函数的访问权限,尽量降低类对象对其它对象的引用次数;

    例如,下图1未使用迪米特原则,图2使用了迪米特原则:

    image-20220621230317248

    image-20220620013730370

23. 面向对象设计模式

是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,设计模式通过实现面向对象七大原则,从而达到了代码复用、增加可维护性的目的。

  • 单例模式:这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

    • 为避免其它程序过多地建立该类的对象,先禁止其它程序建立该类对象实例;
    • 饿汉式:对象预先加载,线程是安全的,在类创建好的同时对象生成,调用获得对象实例的方法反应速度快,代码简练;
    • 懒汉式:对象延迟加载,效率高,只有在使用的时候才实例化对象,若设计不当线程会不安全,代码相对于饿汉式复杂,第一次加载类对象的时候反应不快。
  • 建造者模式:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。

    • 实例:

      用建造者(Builder)模式描述客厅装修。

      分析:客厅装修是一个复杂的过程,它包含墙体的装修、电视机的选择、沙发的购买与布局等。客户把装修要求告诉项目经理,项目经理指挥装修工人一步步装修,最后完成整个客厅的装修与布局,所以本实例用建造者模式实现比较适合。

      这里客厅是产品,包括墙、电视和沙发等组成部分。具体装修工人是具体建造者,他们负责装修与墙、电视和沙发的布局。项目经理是指挥者,他负责指挥装修工人进行装修。

      另外,客厅类中提供了 show() 方法,可以将装修效果图显示出来。客户端程序通过对象生成器类 ReadXML 读取 XML 配置文件中的装修方案数据,调用项目经理进行装修。其类图如图所示:

      • 建造者模式的主要优点如下:

        • 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象;
        • 每一个具体建造者都相对独立,与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,扩展方便,符合开闭原则;
        • 可以更加精细地控制产品的创建过程;
      • 其缺点如下:

        • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,不适合使用建造者模式,因此其使用范围受到一定的限制;
        • 如果产品的内部变化复杂,可能会需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加了系统的理解难度和运行成本。
  • 观察者模式:观察者(Observer)是指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。

    • 模式动机:建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。

    • 实例:

      利用观察者模式设计一个程序,分析人民币汇率的升值或贬值对进口公司进口产品成本或出口公司的出口产品收入以及公司利润率的影响。

      分析:当“人民币汇率”升值时,进口公司的进口产品成本降低且利润率提升,出口公司的出口产品收入降低且利润率降低;当“人民币汇率”贬值时,进口公司的进口产品成本提升且利润率降低,出口公司的出口产品收入提升且利润率提升。

      这里的汇率(Rate)类是抽象目标类,它包含了保存观察者(Company)的 List 和增加/删除观察者的方法,以及有关汇率改变的抽象方法 change(int number);而人民币汇率(RMBrate)类是具体目标, 它实现了父类的 change(int number) 方法,即当人民币汇率发生改变时通过相关公司;公司(Company)类是抽象观察者,它定义了一个有关汇率反应的抽象方法 response(int number);进口公司(ImportCompany)类和出口公司(ExportCompany)类是具体观察者类,它们实现了父类的 response(int number) 方法,即当它们接收到汇率发生改变的通知时作为相应的反应。下图所示是其 UML 结构图。

      人民币汇率分析程序的结构图

    • 观察者模式的优点:

      • 具体目标和具体观察者是松耦合关系,观察者接口的引入降低了系统的复杂度;
      • 观察模式满足“开-闭原则”。目标接口仅仅依赖于观察者接口,系统的可复用性和可扩展性得到提升。
    • 观察者模式的缺点:

      • 如果一个观察者关联很多实例的话,将所有的实例都通知到会花费很多时间;
      • 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃;
      • 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
  • 中介者模式:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。

    • 实例:

      用中介者模式编写一个“房地产交流平台”程序。

      分析:首先,定义一个中介公司(Medium)接口,它是抽象中介者,它包含了客户注册方法 register(Customer member) 和信息转发方法 relay(String from,String ad);再定义一个房地产中介(EstateMedium)公司,它是具体中介者类,它包含了保存客户信息的 List 对象,并实现了中介公司中的抽象方法。

      然后,定义一个客户(Customer)类,它是抽象同事类,其中包含了中介者的对象,和发送信息的 send(String ad) 方法与接收信息的 receive(String from,String ad) 方法的接口,由于本程序是窗体程序,所以本类继承 JPmme 类,并实现动作事件的处理方法 actionPerformed(ActionEvent e)。

      最后,定义卖方(Seller)类和买方(Buyer)类,它们是具体同事类,是客户(Customer)类的子类,它们实现了父类中的抽象方法,通过中介者类进行信息交流,其结构 UML 图如下:

    • 中介者模式的优点为:

      • 类之间各司其职,符合迪米特法则;
      • 降低了对象之间的耦合性,使得对象易于独立地被复用;
      • 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展;
    • 中介者模式的缺点为:

      • 中介者模式将原本多个对象直接的相互依赖变成了中介者和多个同事类的依赖关系。当同事类越多时,中介者就会越臃肿,变得复杂且难以维护。

24. 复用

有两种类型的复用:生产者复用和消费者复用;

  • 生产者复用:正在设计的构件要在以后的应用中进行复用;
  • 消费者复用:正在使用的构件是之前为其它应用开发的构件;

25. 编程过程

XP、结对编程、融合、小组协同;

26. 软件测试术语

  • 错误(error):往往是人为导致的故障;
  • 故障(fault):程序中不正确的步骤,过程或者数据定义,导致程序出现了非故意的、不可预料的行为,通常是由 error 导致的;
  • 失效(failure):一个系统或者组件不能完成它被要求的功能,通常是 fault 导致的;

27. 故障类型

  • 算法故障:源代码编写或算法设计上的一些错误导致的故障;
  • 计算故障和精度故障:算术表达式错误或计算结果未达到要求的精度;
  • 文档故障:文档与程序实际做的事情不一致;
  • 能力故障或边界故障:系统活动到达指定的极限时,系统性能会变得不可接受;
  • 计时故障或协调故障:实时系统的并发进程之间同步互斥关系出现故障;
  • 吞吐量故障或性能故障:系统不能以需求规定的速度执行;
  • 标准和过程故障:代码规范或风格不合符组织的要求;

28. 软件测试基本步骤

img

  • 单元测试:将系统中的每个程序构件与其它构件隔离,单独测试每个构件是否能正常运行;
  • 集成测试:确保构件之间的接口能正常运行,各构件正常协作;
  • 功能测试:是对系统的整体评估,以确定集成的系统是否确实执行了需求规格中描述的功能,其结果是一个可运转的系统;
  • 性能测试:测试系统在客户的实际工作环境中能否成功执行,其结果是一个确认的系统;
  • 验收测试:与客户交换意见,以确定满足了客户的预期,与客户进行确认后完成验收;
  • 安装测试:将验收后的系统安装在它实际工作的环境中,确保能正确工作。

29. 单元测试方法

  • 静态测试(程序不执行):一般是检查代码的风格和规范。

    • 静态分析器(自动工具);
    • 代码评审(人工方式);
  • 动态测试(程序执行):通过选择适当的测试用例,执行程序。

    • 黑盒测试(测试功能):不考虑程序的内部结构与特性,只根据程序功能或程序的外部特性设计测试用例。

      • 等价类分类法:将可能的输入划分成若干等价的类,每一个类选择一个测试用例;

        • 有效等价类:有意义、合理的输入数据,用于评估系统功能;
        • 无效等价类:无意义、不合理的输入数据,用于检测程序异常;

        例如,注册某网站。要求:用户名的长度为812的数字与字母组合而成的字符,,密码长度为616位的数字、字母的组合。请写出测试案例:

        img

        确定了等价类之后我们就可以设计测试用例了,测试用例需要覆盖到所有的等价类,即有效等价类和无效等价类。具体情况请看下表:

        img

      • 边值分析法:对输入的边界值进行测试,例如,对16-bit 的整数而言 32767 和 -32768 是边界;屏幕上光标在最左上、最右下位置。

      • 错误推测法:在测试程序时,人们可以根据经验或直觉推测程序中可能存在的各种错误,从而有针对性地编写检查这些错误的测试用例的方法。

      • 因果图法:适合输入条件比较多的情况,可以测试所有的输入条件的排列组合。“ 因 ” 就是输入条件,“ 果 ” 就是输出结果。

    • 白盒测试(测试结构):分析程序的内部逻辑结构,注意选择适当的覆盖标准,设计测试用例,对主要路径进行尽可能多的测试。

      白盒法又称为逻辑覆盖法,常用的逻辑覆盖标准:

      • 语句覆盖:程序中每个语句至少都能被执行一次;
      • 判定覆盖:程序中每个判定至少为 truefalse 各一次;
      • 条件覆盖:判定语句中的每个条件表达式都至少为 truefalse 各一次,满足条件覆盖的,不一定满足判定覆盖;
      • 判定/条件覆盖: 同时满足判定覆盖和条件覆盖;
      • 条件组合覆盖: 判定中条件的各种可能组合都至少出现一次,例如判定语句 in 个条件,每个条件有 truefalse 选项,则至少需要 2^n 个用例才能覆盖语句 i

30. 集成测试

把功能模块或程序单元组合起来进行测试,发现模块在组合过程中的缺陷。

  • 驱动模块:用于模拟待测模块的上级模块。驱动模块在集成测试中接受测试数据,将相关的数据传送给待测模块,启动待测模块,并打印出相应的结果;
  • 桩模块:用于模拟待测模块工作过程中所调用的模块。桩模块由待测模块调用,它们一般只进行很少的数据处理,以便于检验待测模块与下级模块的接口。

集成测试的分类:

  • 非增量式集成策略:对所有模块进行单元测试后,将各模块连接起来,把连接后的程序当作一个整体进行测试。

  • 增量式集成策略:逐次将未曾集成测试的模块和已经集成测试的模块(或子系统)结合成程序包,再将这些模块集成为较大系统,在集成的过程中边连接边测试,以发现连接过程中产生的问题。

    增量式集成测试又可以分为三种不同的方法:

    • 自顶向下增量式测试:模块集成的顺序是首先集成主控模块(主程序),然后依照控制层次结构向下进行集成。从属于主控模块的按 DFSBFS 方式集成到结构中去。

      整个过程由 3 个步骤完成:

      • 主控模块作为测试驱动器;
      • 下层的桩模块一次一次地被替换为真正的模块;
      • 每个模块被集成时,都必须进行单元测试。重复第2步,直到整个系统被测试完成。

      例题:对如下结构采用自顶向下深度优先策略进行测试:

      image-20220621193102936

      image-20220621193114024

      优缺点分析:

      • 优点:①较早地验证了主要控制和判断点;②可以首先实现和验证一个完整的软件功能;③功能较早证实,带来信心;④只需一个驱动,减少驱动器开发的费用;
      • 缺点:①桩的开发量大;②底层验证被推迟;
      • 适用范围:①产品控制结构比较清晰和稳定;②高层接口变化较小;③底层接口未定义或经常可能被修改;④产品控制组件具有较大的技术风险,需要尽早被验证;⑤希望尽早能看到产品的系统功能行为。
    • 自底向上增量式测试:最常用的集成策略,从具有最小依赖性的底层组件开始,按照依赖关系树的结构,逐层向上集成,以检验系统的稳定性。

      整个过程由 4 个步骤完成:

      • 起始于模块依赖关系树的底层叶子模块;
      • 使用驱动模块对步骤1选定的模块进行测试;
      • 用实际模块代替驱动模块,与它已测试的直属子模块组装成一个更大的模块进行测试;
      • 重复上面的行为,直到系统最顶层模块被加入到已测系统中。

      image-20220621193322274

      优缺点分析:

      • 优点:①对底层组件行为较早验证;②工作最初可以并行集成,比自顶向下效率高;减少了桩的工作量;③能较好锁定软件故障所在位置。

      • 缺点:①驱动的开发工作量大;②对高层的验证被推迟,设计上的错误不能被及时发现。

      • 适用范围:①适应于底层接口比较稳定;②高层接口变化比较频繁;③底层组件较早被完成。

    • 三明治增量式测试:把系统划分成三层,中间一层为目标层,目标层之上采用自顶向下集成,之下采用自底向上集成。

      image-20220621193643887

      整个过程由 4 个步骤完成:

      • 首先对目标层之上一层使用自顶向下集成;
      • 其次对目标层之下一层使用自底向上集成;
      • 其三,把目标层下面一层与目标层集成;
      • 最后,把三层集成到一起。

      优缺点分析:

      • 优点:集合了自顶向下和自底向上两种策略的优点;
      • 缺点:中间层测试不充分,难以选择;
      • 适用范围:适应于大部分软件开发项目。

31. 软件缺陷数目估计方法

  • 播撒模型:

    • Mills 模型:人工随机置入错误 M 个错误,测试得出 m 个人工置入的错误,n 个程序固有的错误,则估算系统固有错误为:
      N = n × M m N=\frac{n×M}{m} N=mn×M

    • Hyman 模型:两人同时进行测试,A 发现 n 个错误,B 发现 m 个错误,其中共同错误有 q 个,则估算系统的固有错误为:
      N = m × n q N=\frac{m×n}{q} N=qm×n

  • 静态模型:根据软件的规模和复杂性进行估计。

  • 根据测试覆盖率的预测模型:

    image-20220621201704535

2. 综合题

2.1 绘制 AOE 网

步骤:

  • 计算事件的最早发生时间表,earliest(j) = max{earliest(i) + w(i, j)}
  • 计算事件的最晚发生时间表,latest(i) = mim{latest(j) - w(i, j)}

例1

如下图所示的AOE网(弧上权值代表活动的持续天数,求:

1)绘制事件的最早发生时间和最晚发生时间;

2)绘制活动的最早开始时间和最晚开始时间;

3)哪些是关键活动,给出关键路径;

4)完成此工程最少所需要多少天。

image-20220619012106606

image-20220619012125319

2.2 COCOMO 模型

基本工作量计算公式如下:
E = a × K L O C b × F E=a×KLOC^b×F E=a×KLOCb×F

① 基本 COCOMO:

方式 a b
有机 2.4 1.05
半有机 3.0 1.12
嵌入式 3.6 1.2

E = a × K L O C b × 1 E=a×KLOC^b×1 E=a×KLOCb×1

一个 33.3 KLOC 的软件开发项目,属于中等规模、半有机型的项目,采用基本COCOMO:a = 3.0,b = 1.12,则:
E = 3.0 × 33. 3 1.12 × 1 = 152 p m E= 3.0×33.3^{1.12}×1=152pm E=3.0×33.31.12×1=152pm

② 中等 COCOMO:

方式 a b
有机 2.8 1.05
半有机 3.0 1.12
嵌入式 3.2 1.2

image-20220619020107785
F = ∏ i = 1 17 E M i F=\prod_{i=1}^{17}{EM_i} F=i=117EMi

E = a × K L O C b × F E=a×KLOC^b×F E=a×KLOCb×F

一个 33.3 KLOC 的软件开发项目,属于中等规模、半有机型的项目,采用中等 COCOMO 模型。 a = 3.0,b=1.12,则:
F = 0.70 × 0.85 × . . . × 1.15 = 1.09 F=0.70×0.85×...×1.15=1.09 F0.70×0.85×...×1.15=1.09

E = 3.0 × 33. 3 1.12 × 1.09 = 16 p m E=3.0×33.3^{1.12}×1.09=16pm E=3.0×33.31.12×1.0916pm

③ 高级 COCOMO:

image-20220619020218935
b = 0.91 + 0.01 ∑ i = 1 5 b i b=0.91+0.01\sum_{i=1}^{5}{b_i} b=0.91+0.01i=15bi
image-20220619020107785
F = ∏ i = 1 17 E M i F=\prod_{i=1}^{17}{EM_i} F=i=117EMi

E = a × K L O C b × F E=a×KLOC^b×F E=a×KLOCb×F

a 是校正常数,通常取值 2.94(根据公司大量数据进行调整)。

2.3 决策树分析

image-20220619022927736

2.4 E-R 图

在 ER 图中有如下 4 个成分:

image-20220619165642322

  • 矩形框:表示实体,在框中记入实体名;
  • 菱形框:表示实体和实体之间的联系,在框中记入联系名;
  • 椭圆形框:表示实体或联系的属性,将属性名记入框中,对于主属性名应加入下划线;
  • 连线:实体与属性之间;实体与联系之间;联系与属性之间用直线相连,并在直线上标注联系的类型;
    • 对于一对一联系(1 ∶1):要在两个实体连线方向各写1;
    • 对于一对多联系(1 ∶N) :要在一的一方写1,多的一方写N;
    • 对于多对多关系(N∶M) : 则要在两个实体连线方向各写 N,M。

image-20220619170008674

例题1:用图书、作者两个实体及其属性和联系构建E-R图。

  • 图书的属性:书号、书名、出版社、价格;
  • 作者的属性:身份证号、姓名、年龄;

image-20220619170143792

例题2:某企业集团有若干工厂,每个工厂生产多种产品,且每一种产品可以在多个工厂生产,每个工厂按照固定的计划数量生产产品,计划数量不低于300;每个工厂聘用多名职工,且每名职工只能在一个工厂工作,工厂聘用职工有聘期和工资。工厂的属性有工厂编号、厂名、地址,产品的属性有产品编号、产品名、规格,职工的属性有职工号、姓名、技术等级。

image-20220619170215679

2.5 UML 图

类图以反映类的结构(属性、操作)以及类之间的关系为主要目的,描述了软件系统的结构,是一种静态建模方法。从上到下分为三部分,分别是类名、属性和操作。

image-20220619170737483

类图中的关系:

  • 依赖关系:描述了一个类的变化对依赖于它的类产生影响的情况;

    虚线 + 箭头表示

    image-20220619172600035

    image-20220619172647145

    image-20220619174053092

  • 关联关系:用带箭头的线段表示,表示类之间的联结,一个类使用了另一个类的方法;

    image-20220619171646190

    image-20220619170904904

    image-20220619173949000

  • 聚合关系:特殊关联关系,指明一个聚集(整体)和组成部分之间的关系。例如,多名学生聚合成了一个班级,学生不会因为班级的解散而无法存在,教室需要同时知道班级和学生的信息,二者的生命周期是独立的;

    image-20220619173048244

image-20220619171140481

  • 组合关系:语义更强的聚合,部分和整体具有相同的生命周期。例如,学生由器官组成,器官的生命周期被严格封装在学生中,只需要了解学生的信息即可;

    image-20220619172342439

    image-20220619172346550

  • 泛化关系:在面向对象中一般称为继承关系,存在于父类与子类、父接口与子接口之间;

    image-20220619172414820

    image-20220619172428749

    image-20220619174021641

  • 实现关系:对应于类和接口之间的关系;

    虚线 + 空心三角形表示

    image-20220619172528390

    image-20220619174038038

2.6 Petri 网

例题1

image-20220619181233222

image-20220619181240509

例题2

有一工业生产线,要完成两项操作,分别为变迁 t1 和 t2 表示,变迁 t1 将进入生产线,半成品 s1s2 用两个部件 s3 固定在一起,后形成中间件 s4。然后第2个变迁 t2 将 s4 和 s5 用 3 个部件 s3 固定在一起形成中间件 s6。完成 t1 和 t2 都需要用到工具 s7。

假设受空间限制,s2、s5 最多不能超过 100 件, s4 最多不能超过 5 件,s3 最多不能超过 1000 件。

其 Petri 网结果如下:

image-20220619181425312

2.7 数据流图

在这里插入图片描述

顶层图:中间的椭圆是需要开发的系统 , 周边的矩形表示外部实体人或组织;

中层图:将 “顶层数据流图” 进行细化,外部实体不变;

底层图:针对每个加工 节点 , 将其拆分 , 绘制其中的更详细的数据流转情况;

**例题:**图书预订系统:书店向顾客发放订单,顾客将所填订单交由系统处理,系统首先依据图书目录对订单进行检查并对合格订单进行处理,处理过程中根据顾客情况和订单数目将订单分为优先订单与正常订单两种,随时处理优先订单,定期处理正常订单。最后系统根据所处理的订单汇总,并按出版社要求发给出版社。

  • 第一步,画出关联数据流图:

    image-20220619183029996

  • 第二步,逐层分解加工,画出下层 DFD:

    image-20220619183048739

  • 第三步,细化中间过程,画出底层 DFD:

    image-20220619183121047

2.8 UML 用例图

类似于顶层的数据流图,描述了系统和用户的上层交互情况。

  • 用例图中的关系及解释

    image-20220619183603314

  • 例题1:

    参与者:经理,安全主管,保安

    用例:管理人事,批准预算,批准安全证书,监视周边

    image-20220619183640078

  • 例题 2:

    短途旅行但汽车的油不足以应付全部路程。那么为汽车加油的动作在旅行的每个场景(事件流)中都会出现,不加油就不会完成旅行。吃饭则可以由司机决定是否进行,不吃饭不会影响旅行的完成。

    image-20220619183737942

2.9 故障树分析

故障树是一种为研究系统某功能故障而建立的一种倒树状的逻辑因果关系图。

img

割集树的边缘就是故障树的割集,表示引起树顶失效所需事件的最小集合。

若已知故障树的割集以及底事件发送的概率,则顶事件发送的概率为各割集元素发生概率之和。

猜你喜欢

转载自blog.csdn.net/Elford/article/details/125464380