如何理解类似于UML中的反身关联的“反身聚合”关系?

3
这个类图代表什么?反射关联的类图使用实线和箭头,但这里被空心菱形所取代。它与递归有关吗?这个类图将生成什么?最好能给一个例子。此外,这种递归关系应该是一对多的,如果要存储在数据库中,如何建立表格。

感谢您的回复@Christophe。我明白了,也就是说,这种类图可以描述树形结构。通俗地讲,它可以被视为一个大学,有多个系,每个系包含多个专业,而这些子节点只有一个共同的父节点。但是,如果您想设计一个单元程序的类图,如何绘制边界类、控制类和实体类,以更好地表达面向对象设计的要点呢?如果我能举个例子就太好了。 - mc_wendy
有许多方法。实体-边界-控制需要从用例开始,因为控制类对应于用例,边界对应于它们与角色的关联。还有其他OO设计方法,因此也取决于架构选择。但是,只在一个图表中拥有所有类仅适用于小型系统。因此,流行的方法是从域模型(即ECB中的实体)开始,并使用其他模型来显示域类如何与UI和应用程序基础结构合作。 - Christophe
但这些是不同的问题。在StackOverflow上,每个问题都应该有非常狭窄的焦点,以便可以客观地回答它。 - Christophe
我认为我有宏观的理解,非常感激。 - mc_wendy
3个回答

1
这是什么意思?
这个类图表示一个 Unit 实例可以与多个其他 Unit 实例关联:
  • 空心的聚合钻石只是一种“建模安慰剂”:它不会改变图表的含义,只是暗示这种关联表示某种分组。

  • 反身关联意味着将一个类与其自身相关联。与递归没有直接关系,正如此SO答案所解释的那样

  • 然而,递归算法是探索这种关联的好选择(例如,查找所有间接与特定实例相关的Unit实例)。在数据库环境中,“递归关联”一词有时代替“反身关联”,因为使用递归连接来实现它们。

请注意,1 应该更改为 0..1,因为 1 表示恰好为 1,这将意味着在向上导航时有无尽的循环。
它是什么样子?
由于这是一对多关联,您可以将其视为树木的森林:每个 Unit 实例可以是某些分支的起点,并且可能会共享公共分支(无稽之谈:最多只有一个父级)。

enter image description here

是如何生成/实现的?

让我们添加一些角色来更好地谈论聚合的结束:

enter image description here

代码生成将取决于工具和目标语言。但是,具有聚合的模型和具有简单关联的模型很可能会生成完全相同的代码,例如:

class Unit { // Java
    private String id;
    private Unit[] child; // java objects are sharable by default 
    private Unit parent; // unless we make it non navigable in that direction
    ...
}

在关系型数据库管理系统中,表格看起来非常相似。关系模型允许使用仅有一列的双向链接:
ID (PK)  |  Parent (FK, nullable)
----------------------------------
w        |
u        |
u1       |  u
u2       |  u 
u3       |  u
u21      |  u2
u31      |  u3
u32      |  u3 
v        |
v2       |  v

一种自连接或递归CTE将允许利用反身关联查询数据。

@qwerty_so 我认为我们可以达成一致的看法,即不推荐使用它。然而规格定义了共享聚合。甚至建议它可以用来表示某种分组(该语句几乎是从规格中复制粘贴的),即使没有指定的语义。因此,我们也不能忽视它。像任何安慰剂一样,您可以使用它或不使用它,结果是相同的,但有些人会感觉更好;-) - Christophe
OP问的是含义,而不是应该是什么。你展示的代码是模型应该是什么,而不是模型现在是什么。 - Jim L.
1
@JimL。感谢您强调我们不同的方法。我看到你选择了强调1重复性,这很好地解决了问题。我认为1是一个简单的错误,OP更关心有无钻石符号之间的区别。由于我已经阅读了无数关于聚合与关联的矛盾说法,我推断这使大多数OP感到困惑。也许我的理解是错的。然而,Java代码显示了什么以及应该是什么:如果未显示构造函数,则Java类中的0..1或1重复性没有区别;-) - Christophe
1
@JimL。我看到qwerty_so也认为聚合是问题所在,并没有解决1个不一致性。 - Christophe
此外,在SQL中,OP的模型不应允许父级Unit FK列为空。 - Jim L.
显示剩余2条评论

1
在UML中,这个类表示每个单元都被聚合到另一个单元中。
UML标准并不涵盖代码生成,因此将其解释为代码取决于您选择的工具。每个专有的代码生成工具都应该停止并提供一个额外的构造函数,用于创建引用自身的新单元。否则,调用者第一次传递给构造函数的单元是什么?
解决问题的其他方法包括采用这个UML模型的开放世界解释(其中并非所有真实信息都存在,如OWL的情况),或者放宽多重性为0..1。

为什么代码生成工具会因错误而停止:拥有自引用循环数据结构是完全合法的(循环缓冲区就是一个完美的例子,谁知道循环多缓冲区不是另一个新的有前途的发明;-))。此外,为什么代码生成工具会由于反射关联而递归?生成代码并不使用类实例,因此潜在的循环不会影响代码生成。任何代码生成器的快速测试都可以证明这一点。 - Christophe
按照模型,任何单元没有引用另一个单元都是错误的,这是不可能的(除非一个单元引用自身)。 - Jim L.
我之前评论中的括号让我意识到我错过了另一个可能性。我相应地更新了我的答案。 - Jim L.
构造函数不在模型中。因此,代码生成不会受到任何影响。实际上,我快速测试的那个只是生成了一个带有属性的类。代码生成器只生成存在的内容,而不是应该存在的内容;-)如果需要添加构造函数,则建模者必须指定与模型一致的构造函数。可以预见没有问题创建自引用单元的构造函数;由于操作完全未指定,因此这完全是推测性的。 - Christophe

0

UML 2.5 的第110页针对这种关系阐述:

shared - 表示该属性具有共享聚合语义。共享聚合的精确语义因应用领域和建模者而异。

简而言之:它的意思取决于你定义时的含义。


关于历史的注释

在UML 1.5中,只有聚合。然后在2.0中引入了共享聚合。在UML 2.0的第80页上:

表示该属性具有共享聚合。

并且更进一步地说:

共享聚合的精确语义因应用领域和建模者而异。

显然,后一句话还没有传达给普通人,你会发现各种解释它的含义。

幸运的是,在UML 2.5中,这两个句子被合并成一个段落。即在我著名的第110页。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接