这三个类之间的(类图)是什么关系?

时间:2021-05-18 13:19:20

标签: ruby uml class-diagram

我的代码如下:

class Synchronization

  def initialize

  end
  
  def perform
    detect_outdated_documents
    update_documents
  end

  private

  attr_reader :documents


  def detect_outdated_documents
    @documents = DetectOutdatedDocument.new.perform
  end

  def update_documents
    UpdateOutdatedDocument.new(documents).perform
  end

@documents 是我从 DetectOutdatedDocument 中的方法返回的哈希数组。 然后我使用这个 Hash 数组来初始化 UpdateOutdatedDocument 类并运行 perform 方法。

这样的事情正确吗? 还是应该使用关联或其他方式?

class diagrams

2 个答案:

答案 0 :(得分:2)

Ruby 到 UML 的映射

我不是 Ruby 专家,但鉴于其 syntax,我从您的代码段中了解到:

  • 有一个 Ruby 类 Synchronization:那是一个 UML 类
  • Ruby 类有 4 个方法 initializeperformdetect_outdated_documentsupdate_documents,最后两个是私有的。这将是 4 个 UML 操作。
  • initializeconstructor,因为它是空的,所以你没有在你的 UML 类图中提到它,没关系。
  • Ruby 类有 1 个实例变量 @documents。在 UML 中,这将是关联端的属性或角色。
  • Ruby 类有一个使用 attr_reader 创建的 getter。但由于它在一个私有部分,它的可见性应该是 -。此 other answer 解释了如何在 UML 中优雅准确地使用 getter 和 setter(非常感谢 @engineersmnky 对 Ruby 中 getter 的解释,并纠正了我最初在这方面的误解)
  • 我知道 SomeClass.new 在 Ruby 中创建了一个类 SomeClass 的新对象。

Ruby 和 UML 中的动态类型

UML 类图基于明确定义的类型/类。您通常会仅与已知的类确定关联、聚合和组合,这些类肯定与这些类有稳定的关系。 Ruby 是动态类型的,关于实例变量的所有已知信息是它的类型为 Object,这是 Ruby 中可能的最高泛化。

此外,Ruby 方法返回其执行路径中最新语句/表达式的值。如果您不关心对象的返回值,只需将其标记为 Object(感谢 engineersmnky 的解释)。

补充说明:

  • UML 中没有 void 类型(另请参阅此 SO question)。不返回任何内容的 UML 操作只是一个没有指示返回类型的操作。
  • 还请记住,使用不属于 UML 标准的类型(例如 ArrayHashObject、...)将假设使用特定于语言的 UML profile

基于所有这些,并考虑到数组也是一个 Object,您的代码将导致一个非常简单的 UML 图,有 3 个类,它们都是 Object 的特化,以及一个SynchronizationObject 之间的一对多关联,角色 @documents 位于 Object 端。

这一切都是我们所希望的吗?

非常通用的类图,也许可以很好地匹配实现。但它可能无法准确代表设计。

您有权在 UML 中对独立于实现的设计进行建模。因此,如果实例变量的类型是设计已知的(例如,您希望它是某种类型,并通过初始化和 API 设计确保该类型将被强制执行),即使它偏离了代码:

  • 您已经完成了一些手动类型推断来推断 UML 操作的返回类型。由于所有 Ruby 方法都会返回某些内容,因此我们希望所有 Ruby 方法至少有一个 Object 返回类型。但是您可以不指明任何返回类型(相当于 void 的 UML)来表示返回值并不重要。
  • 您还对实例变量(UML 属性)进行了一些类型推断:您阐明了它可以采用的唯一值是 DetectOutdatedDocument.new.perform 返回的值。
  • 您的图表表明该类与未指定数量的 DetectOutdatedDocument 对象相关,我们猜测这是因为 @documents 的可能值。并且该属性表示为对象数组。在图表上同时显示两者是非常误导的。所以我建议删除 document 属性。相反,更喜欢在 document 一侧的关联端使用 DetectOutdatedDocument 角色。对于非 Ruby 本地读者来说,这将极大地阐明为什么图表上有第二个类。 :-)(花了我一段时间)
  • 现在您不应该使用黑色菱形进行构图。因为 documents 有一个公共阅读器;因此其他对象也可以分配给相同的文档。由于 Ruby 似乎对对象具有引用语义,因此副本将引用相同的对象。这充其量是共享聚合(白色菱形)。而且由于 UML 没有很好地定义聚合语义,您甚至可以显示一个简单的关联。

最后一点:根据您显示的代码,我们无法确认 UpdateOutdatedDocumentDetectOutdatedDocument 之间存在聚合。如果你确定有这样的关系,你可以保留它。但是,如果它仅基于您向我们展示的代码段,请删除聚合关系。您最多可以显示使用依赖性。但通常在 UML 中,如果它是关于方法体的,你不会显示这样的依赖关系,因为操作可以非常不同地实现,而不必具有这种依赖关系。

答案 1 :(得分:0)

在发布的代码中没有关系,无论是 UML 还是其他。事实上,乍一看它可能看起来就像一个 Synchronization has-many @documents,但变量及其内容从未定义、初始化或分配。

如果这是家庭作业,您可能需要询问您的导师目标是什么,正确答案应该是什么。如果它是一个真实世界的项目,那么您还没有做到以下几点:

  1. 定义了像 Document 这样的合作者对象
  2. 以同步类可访问的方式初始化@documents
  3. 允许你的类方法接受任何依赖注入

如果没有列出至少一项,您的 UML 图就不能真正适合发布的代码。

相关问题