UML - 关联还是聚合(简单代码片段)

5

我为有多少本书相互矛盾感到疯狂。

Class A {} class B {void UseA(A a)} //some say this is an association,
no reference is held but communication is possible
Class A {} class B {A a;} //some say this is
    aggregration, a reference is held

但许多人认为持有一个引用仍然只是一种关联,而对于聚合,他们使用列表-在我看来这是相同的,它仍然是一个引用。
我很困惑,我想了解这个问题。
例如:在这里:http://aviadezra.blogspot.cz/2009/05/uml-association-aggregation-composition.html - 强关联和聚合之间有什么区别,在这两种情况下,作者都使用字段存储引用。
另一个例子: 这被称为关联: enter image description here 而这被称为聚合: enter image description here
public class Professor {
  // ...
}

public class Department {
  private List<Professor> professorList;
  // ..

}

再一次,有什么不同吗?在两种情况下都是引用。


你的“参考”是关于UML导航性,而UML聚合则是关于“整体/部分关系”。 - xmojmr
它明确提到一个情况是关联,而另一个情况是聚合。 - John V
聚合是一种二元关联。关联的属性aggregation: AggregationKind决定了类型。请参见www.omg.org/spec/UML/2.4.1/Superstructure中的“内核包类图7.12”。如果需要使用“列表”来保存“引用”,则由UML multiplicity确定。如果关联不可导航,则根本没有“引用”。其中一些术语是正交的,而另一些则是特殊情况(子类)。我建议您选择一本好书(例如uml-diagrams.org)并使用它来做些什么 - xmojmr
1
谢谢。 我已经尝试过了,但正如我在帖子中提到的那样,很多书籍对这一点持不同意见。 有些人说在字段中引用对象是一种关联,而有些人则说它是一种聚合。 像我发布的示例中,教授和课程之间有什么区别? 如果能得到答案,我将不胜感激。 - John V
没有区别。Department-CourseDepartment-Professor都是UML关联。同时,这两个关联都可以标记为UML聚合(根据特定大学的“业务规则”,甚至可以标记为UML组合)。 - xmojmr
4个回答

5
这个问题已经被问过很多次,也将会被问很多次,因为很多人,包括许多高知名度开发者,对这些术语的含义感到困惑,这些术语已经在UML中定义。由于这个问题被问了很多次,也回答了很多次。比如这个答案。我试图总结一下UML的定义。
两个类之间的关联不是通过方法参数建立的,而是通过引用属性(类属性)建立的,其范围/类型是关联的类。如果方法参数的类型是一个类,这并不建立一种关联,而是一种依赖关系。
首先理解关联的逻辑概念非常重要,然后再看它们如何编码。对象类型之间的关联分类了这些类型的对象之间的关系。例如,下面显示的类图中的关联Committee-has-ClubMember-as-chair,可能分类FinanceCommittee-has-PeterMiller-as-chair、RecruitmentCommittee-has-SusanSmith-as-chair和AdvisoryCommittee-has-SarahAnderson-as-chair之间的关系,其中对象PeterMiller、SusanSmith和SarahAnderson的类型是ClubMember,并且对象FinanceCommittee、RecruitmentCommittee和AdvisoryCommittee的类型是Committee。
关联总是通过引用属性进行编码,其范围/类型是关联的类。例如,像这样:
class Committee { ClubMember chair; String name;}

在UML中,聚合和组合被定义为特殊形式的关联,意在分类部分-整体关系。对于聚合而言,与组合相反,整体的部分可以与其他整体共享。以下是聚合的示例,其中一门课程可以属于多个学位计划。 An example of aggregation 组合的定义特征是具有排他性(或不可共享)的部分。组合可能会随着整体和其部分之间存在生命周期依赖关系,这意味着当整体被销毁时,其所有部分也会被销毁。但是,这仅适用于某些组合情况,而非全部,并因此不是其确定性特征。以下是一种组合的示例,其中的部分(组件)可以从整体(复合体)中分离出来,因此可以在整体被销毁后继续存在。 enter image description here

UML 对此非常清楚 - 请参阅 UML 2.5 规范的第 112 页(由于太长,我无法在此处复制...)。 - CharlesRivet
非常有趣的回答。我有几个问题:1. 您建议依赖和关联之间的根本区别在于前者具有方法生命周期,而后者具有对象生命周期。您能否提供一段支持最新 U.M.L. 规范的段落?2. 在 U.M.L. 规范中,由于关联不是有向关系的特化,因此关联始终是无向的吗?3. 属性与其类之间的隐式关系是什么类型的:共享聚合、组合聚合还是(非聚合)关联? - Géry Ogam
@Maggyero:1. 在UML中,“依赖”这个术语用于多种不同类型的有向关系。我并没有暗示UML依赖通常具有“方法生命周期”。2. 与数学概念中的关系相反,UML关联在本质上总是无向的,因为它支持其名称所表示的关系(假设有一个)和逆关系。如果在关联的两端都有角色名,则可以在两个方向上阅读它。它是作为单向关联还是双向关联实现的问题与此阅读方向无关。 - Gerd Wagner
  1. 好的,你的意思是关联是一种对称关系,但对称性属性推广到n元关系(即它是一个包含其元组任何排列的元组集合,换句话说,它是一个集合的集合)。
  2. 好的。
  3. 既然依赖被它们所隐含,为什么不将其定义为UML规范中元素层次结构中关联泛化的父级?
- Géry Ogam
@GerdWagner,关于最后一条评论没问题。 “只有链接与参与对象的生命周期绑定。” 好的,但是这些链接可以有更短的生命周期吗?例如方法生命周期,还是必须具有对象生命周期? - Géry Ogam
显示剩余4条评论

1
请参考超级结构2.1.1:
关联可以表示复合聚合(即整体/部分关系)。只有二元关联才能进行聚合。复合聚合是一种强聚合形式,要求部件实例最多只包含在一个复合中。如果复合被删除,则通常会将其所有部分一并删除。注意,在删除复合之前,部分可以(在允许的情况下)从复合中移除,因此不会作为复合的一部分被删除。组合可以在具有传递删除特性的有向无环图中链接;也就是说,删除图的某个部分中的元素也将导致其下方子图中所有元素的删除。聚合由设置为true的关联的部件端上的isComposite属性表示。
可导航性意味着在运行时参与链接(关联的实例)的实例可以从参与关联另一端的实例中高效访问。这种访问方式的确切机制是与实现相关的。如果一个端点不可导航,则可能无法从其他端点访问,如果可以访问,则可能不够有效。请注意,操作UML模型的工具不会阻止从非可导航端口导航关联。
你上面的例子处于不同的抽象层次。 Department/Course 是具体的编程类,而 Department/Professor 则是在某个抽象的业务层次上。虽然没有好的来源(我知道)来解释这个事实,但 compositionaggregation 是你只会在业务层面上使用的概念,几乎不会在编码层面上使用(下面有例外)。当你处于代码层面时,你可以使用在两侧都有角色名称的 Association 更好地生活。角色本身是一个类的属性的不同/冗余呈现,该属性引用相反的类。
聚合作为类之间的强绑定,在数据库建模中使用。在这里,您只能在先删除所有聚合物(或反之亦然:删除主控将强制删除聚合物)后才能删除主控。聚合物不能独立存在。在你的例子中,组合(从我的 POV)是一个愚蠢的构造,因为它假装是一些周聚合物。但那简直是无稽之谈。然后使用关联。只有在业务层面上,您可以尝试将机器零件建模为复合材料。在具体层面上,组合是一个无用的概念。
总之:
如果类之间存在关系,应该将其展示为简单的关联。添加角色等细节有助于讨论领域细节。仅在业务层面建模时鼓励使用组合/聚合,不建议在代码层面使用。

谢谢,但它并没有解答OP中(我附上的例子)实现方面的问题。关联可以是二元的,但为什么必须是聚合呢?两个类只需要相互知道即可。 - John V
抱歉回复如此简短,但仅仅10小时前我回答了几乎相同的问题,而该问题随后已被删除。我稍后会编辑我的回答。 - qwerty_so
当然,非常感谢。我对“仅限二进制”约束感到困惑,因为许多示例显示聚合,而另一个类不知道“父级”。 - John V
可以使用aggr/comp。如果真的有必要,那就去用吧。但在几乎所有情况下,没有必要使用它,你可以简单地使用关联。同时请注意:UML是一个模型,它说可能与现实不同。它专注于某些(重要)方面。 - qwerty_so
2
集合可以简单地表示为关联末尾的基数。集合并不意味着它是一个聚合。那只是胡说八道。 - qwerty_so
显示剩余4条评论

1
我已经写了一篇关于UML Association vs Aggregation vs Composition之间差异的文章,基于实际的UML规范而非书籍作者的解释。
主要结论是:

简而言之,组合是一种具有实际约束和对开发有影响的关联类型,而聚合仅是关联性质的功能指示,没有技术影响。

导航性是完全不同的属性,与聚合类型无关。

0

一方面,UML是一种丰富的语言,意味着描述相同事物的方式不止一种。这就是为什么你会在不同的书中找到不同的描述方式(以及在SO上有冲突的答案)的原因之一。

但是一个关键问题是UML和源代码之间存在巨大的脱节。具体源代码构造在UML中的表示方式,以及反过来,根本不属于UML规范。据我的了解,只有一种语言(Java)拥有官方的UML配置文件,而且已经过时了。

因此,特定源语言构造的表示留给了工具提供商,因此也会有所不同。如果你想从模型生成代码,你必须遵循供应商的约定。反过来,如果你希望从现有源代码生成模型,你将得到基于同样约定的模型。但是,如果你将该模型转移到不同的工具中(这在最好的情况下都很困难)并从中生成代码,你最终得到的代码将不同。

在语言和工具无关的模式下,我认为在哪些情况下使用哪些关系可以在这里找到。值得重复的一点是,在源代码模型中,我不使用无向关联,因为它们在实际代码中没有明显的对应物。如果在代码中类A引用类B,并且B也引用了A,则我会画两个关系。

请注意,如果类A具有范围为B的引用属性,并且B也具有范围为A的引用属性,并且它们彼此是相反的,这表示双向关联,在JPA中通过@OneToMany(mappedBy="...")注释表达引用属性。 - Gerd Wagner
当然,可以找到源语言结构实际上是双向的示例。但在绝大多数编程语言中,绝大多数引用类型结构都是单向的,在这种绝大多数情况下,最好将两个“镜像”引用表示为两个单独的关系。 - Uffe

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