面向对象设计 - OOAD



在分析阶段之后,概念模型将使用面向对象设计 (OOD) 进一步发展成为面向对象模型。在 OOD 中,分析模型中与技术无关的概念被映射到实现类,识别约束并设计接口,从而产生解决方案域的模型。简而言之,构建了一个详细的说明,指定了系统如何基于具体的技术进行构建。

面向对象设计的阶段可以识别为:

  • 定义系统的上下文
  • 设计系统架构
  • 识别系统中的对象
  • 构建设计模型
  • 指定对象接口

系统设计

面向对象系统设计包括定义系统的上下文,然后设计系统的架构。

  • 上下文 - 系统的上下文具有静态部分和动态部分。系统的静态上下文使用整个系统的简单框图设计,该框图扩展为子系统的层次结构。子系统模型由UML包表示。动态上下文描述系统如何与其环境交互。它使用用例图建模。

  • 系统架构 - 系统架构是根据系统的上下文,根据架构设计原则以及领域知识设计的。通常,系统被划分为多个层,每一层都被分解成子系统。

面向对象分解

分解意味着根据分治原则,将大型复杂系统分解成具有较低复杂性的较小组件的层次结构。系统的每个主要组件称为子系统。面向对象分解识别系统中独立的自主对象以及这些对象之间的通信。

分解的优点是:

  • 各个组件的复杂性较低,因此更易于理解和管理。

  • 它能够划分拥有专业技能的劳动力。

  • 它允许替换或修改子系统而不会影响其他子系统。

识别并发性

并发允许多个对象同时接收事件,并且多个活动可以同时执行。并发在动态模型中被识别和表示。

为了启用并发,每个并发元素都被分配一个单独的控制线程。如果并发在对象级别,则两个并发对象被分配两个不同的控制线程。如果单个对象的两个操作本质上是并发的,则该对象将在不同的线程之间拆分。

并发与数据完整性、死锁和饥饿问题相关。因此,每当需要并发时,都需要制定明确的策略。此外,并发需要在设计阶段本身识别,而不能留到实现阶段。

识别模式

在设计应用程序时,一些普遍接受的解决方案被用于某些类别的问题。这些是设计模式。模式可以定义为一组记录在案的构建块,可用于某些类型的应用程序开发问题。

一些常用的设计模式包括:

  • 外观模式
  • 模型视图分离模式
  • 观察者模式
  • 模型视图控制器模式
  • 发布订阅模式
  • 代理模式

控制事件

在系统设计过程中,需要识别可能在系统对象中发生的事件并进行适当处理。

事件是对在时间和空间上具有位置的重要事件的规范。

可以建模四种类型的事件,即:

  • 信号事件 - 一个命名对象由一个对象抛出,并被另一个对象捕获。

  • 调用事件 - 表示操作调度的同步事件。

  • 时间事件 - 表示时间流逝的事件。

  • 更改事件 - 表示状态更改的事件。

处理边界条件

系统设计阶段需要解决整个系统以及每个子系统的初始化和终止。记录的不同方面如下:

  • 系统的启动,即系统从非初始化状态到稳定状态的转换。

  • 系统的终止,即关闭所有正在运行的线程,清理资源以及要发送的消息。

  • 系统的初始配置以及在需要时重新配置系统。

  • 预见系统的故障或意外终止。

边界条件使用边界用例建模。

对象设计

在开发了子系统的层次结构之后,将识别系统中的对象并设计其细节。在这里,设计者详细说明了在系统设计期间选择的策略。重点从应用程序域概念转向计算机概念。分析期间识别的对象被刻画出来以进行实现,目标是最小化执行时间、内存消耗和总体成本。

对象设计包括以下阶段:

  • 对象识别
  • 对象表示,即设计模型的构建
  • 操作分类
  • 算法设计
  • 关系设计
  • 外部交互的控制实现
  • 将包类和关联打包到模块中

对象识别

对象设计的第一个步骤是对象识别。面向对象分析阶段中识别出的对象被分组到类中并被细化,以便它们适合实际实现。

此阶段的功能包括:

  • 识别和细化每个子系统或包中的类

  • 定义类之间的链接和关联

  • 设计类之间的层次关联,即泛化/特化和继承

  • 设计聚合

对象表示

一旦识别出类,就需要使用对象建模技术来表示它们。此阶段主要涉及构建UML图。

需要生成两种类型的设计模型:

  • 静态模型 - 使用类图和对象图来描述系统的静态结构。

  • 动态模型 - 描述系统的动态结构并使用交互图和状态图显示类之间的交互。

操作分类

在此步骤中,通过组合在OOA阶段开发的三个模型(即对象模型、动态模型和功能模型)来定义要对对象执行的操作。操作指定要做什么,而不是如何做。

关于操作,将执行以下任务:

  • 开发系统中每个对象的状体转换图。

  • 为对象接收的事件定义操作。

  • 识别一个事件触发相同对象或不同对象中其他事件的情况。

  • 识别操作中的子操作。

  • 将主要操作扩展到数据流图。

算法设计

使用算法定义对象中的操作。算法是一个逐步解决操作中规定的问题的过程。算法侧重于如何去做。

可能存在多个与给定操作对应的算法。一旦识别出备选算法,就为给定的问题域选择最佳算法。选择最佳算法的指标包括:

  • 计算复杂度 - 复杂度根据计算时间和内存需求来确定算法的效率。

  • 灵活性 - 灵活性决定了所选算法是否可以在各种环境中适当地实现,而不会损失适用性。

  • 可理解性 - 这决定了所选算法是否易于理解和实现。

关系设计

在对象设计阶段需要制定实现关系的策略。需要解决的主要关系包括关联、聚合和继承。

关于关联,设计者应执行以下操作:

  • 确定关联是单向还是双向。

  • 分析关联的路径,并在必要时更新它们。

  • 在多对多关系的情况下,将关联实现为一个不同的对象;或者在一对一或一对多关系的情况下,实现为对其他对象的链接。

关于继承,设计者应执行以下操作:

  • 调整类及其关联。

  • 识别抽象类。

  • 制定规定,以便在需要时共享行为。

控制的实现

对象设计者可以改进状态图模型的策略。在系统设计中,制定了实现动态模型的基本策略。在对象设计期间,此策略得到了恰当的完善,以实现适当的实现。

实现动态模型的方法包括:

  • 将状态表示为程序中的位置 - 这是传统的程序驱动方法,其中控制位置定义程序状态。有限状态机可以实现为程序。转换形成输入语句,主控制路径形成指令序列,分支形成条件,后向路径形成循环或迭代。

  • 状态机引擎 - 此方法通过状态机引擎类直接表示状态机。此类通过应用程序提供的转换和操作集来执行状态机。

  • 并发任务作为控制 - 在这种方法中,对象在编程语言或操作系统中实现为任务。在这里,事件被实现为任务间调用。它保留了真实对象的固有并发性。

包类

在任何大型项目中,将实现细致地划分成模块或包都非常重要。在对象设计过程中,类和对象被分组到包中,以便多个组能够合作完成项目。

打包的不同方面包括:

  • 隐藏内部信息,防止外部查看 − 这允许将一个类视为“黑盒”,并允许更改类实现而无需任何类的客户端修改代码。

  • 元素的一致性 − 如果一个元素(例如类、操作或模块)是根据一致的计划组织的,并且其所有部分都内在相关,从而服务于共同的目标,则该元素具有一致性。

  • 物理模块的构建 − 构建物理模块时,以下指南有所帮助:

    • 模块中的类应该表示相同复合对象中的相似事物或组件。

    • 紧密相关的类应该位于同一个模块中。

    • 不相关或弱相关的类应该放在单独的模块中。

    • 模块应该具有良好的内聚性,即其组件之间具有高度的协作性。

    • 模块应该与其他模块的耦合度低,即模块之间的交互或相互依赖性应该最小。

设计优化

分析模型捕获关于系统的逻辑信息,而设计模型添加细节以支持高效的信息访问。在实现设计之前,应该对其进行优化,以便使实现更有效率。优化的目标是最大限度地减少时间、空间和其他指标方面的成本。

然而,设计优化不应过度,因为易于实现、可维护性和可扩展性也是重要的考虑因素。人们经常看到,经过完美优化的设计效率更高,但可读性和可重用性较差。因此,设计人员必须在这两者之间取得平衡。

可以为设计优化执行的各种操作包括:

  • 添加冗余关联
  • 省略不可用的关联
  • 算法优化
  • 保存派生属性以避免重新计算复杂的表达式

添加冗余关联

在设计优化过程中,检查是否可以推导出新的关联以降低访问成本。尽管这些冗余关联可能不会添加任何信息,但它们可能会提高整个模型的效率。

省略不可用的关联

关联过多可能会使系统难以理解,从而降低系统的整体效率。因此,在优化过程中,所有不可用的关联都被删除。

算法优化

在面向对象的系统中,数据结构和算法的优化以协作的方式进行。一旦类设计到位,就需要优化操作和算法。

算法优化可以通过以下方式获得:

  • 重新安排计算任务的顺序
  • 反转循环的执行顺序(与功能模型中规定的顺序相反)
  • 删除算法中的死路径

派生属性的保存和存储

派生属性是指其值作为其他属性(基属性)的函数计算的属性。每次需要时重新计算派生属性的值是一个耗时的过程。为了避免这种情况,可以计算其值并以计算后的形式存储。

但是,这可能会导致更新异常,即基属性值发生变化而派生属性值没有相应变化。为了避免这种情况,采取以下步骤:

  • 每次更新基属性值时,也重新计算派生属性。

  • 定期批量重新计算和更新所有派生属性,而不是每次更新后都进行。

设计文档

文档是任何软件开发过程中必不可少的部分,它记录了制作软件的过程。对于任何非平凡的软件系统,都需要记录设计决策,以便将设计传达给他人。

使用领域

虽然是次要产品,但良好的文档是必不可少的,尤其是在以下领域:

  • 在由多位开发人员开发的软件设计中
  • 在迭代式软件开发策略中
  • 在开发软件项目的后续版本中
  • 用于评估软件
  • 用于查找测试条件和领域
  • 用于维护软件。

内容

有益的文档应主要包括以下内容:

  • 高级系统架构 − 流程图和模块图

  • 关键抽象和机制 − 类图和对象图。

  • 说明主要方面行为的场景 − 行为图

特点

良好文档的特点包括:

  • 简洁明了,同时准确、一致和完整

  • 可追溯到系统的需求规范

  • 结构良好

  • 图示而非描述性

广告