关联 vs 聚合

33

我已经查阅了很多关于这些内容的信息,但是不明白它们之间的区别在哪里?在Fowler的UML Distilled中,作者表示聚合(Aggregation)毫无意义,因此建议在图表中不要使用。

请解释一下,我应该何时使用它们以及如何影响Java代码。


你可能不应该将这个标记为OOP和UML。在面向对象编程中,这些术语的含义与在UML中的含义不同。 - keithwill
10
不,UML是一种图形化的面向对象设计符号,所以它们应该意味着相同的事情。 - duffymo
1
UML不仅仅是一种图形符号,尽管图形符号似乎是唯一有用的部分。 - Goran Jovic
这篇文章关于关联,聚合和组合的区别可能会对您有用。 - Iman Mahmoudinasab
6个回答

166

类之间有四种关系:

  1. 关联: 使用
    例如:一个类Man使用一个类Pen(当人死亡时笔仍然存在)
  2. 聚合: 拥有
    例如:一个类Man拥有一个类Car(当人死亡时汽车仍然存在)
  3. 组合: 拥有并且负责销毁
    例如:一个类Man拥有一个类Heart(当人死亡时心脏也会停止工作)
  4. 继承:
    例如:一个类Man是一个类Human(人类是人的一种)

类之间的关系

继承 > 组合 > 聚合 > 关联


19
建议用“包含”替换“拥有”。可以说,“拥有”对应于聚合。 - reinierpost
1
仅翻译文本内容:+1 代表优秀的示例!! - Ravi
你忘记了依赖关系(UML),在面向对象编程的上下文中,它被广泛使用,特别是涉及内聚性和依赖注入等概念。 - gustavogbc
5
+1,但是集合和关联之间的区别有点令人困惑——一个人大多数情况下也可以拥有一支笔使用一辆车。所有权很重要。更好的例子:关联 - 人去了医院,聚合 - 人拥有一辆车。 - nawfal
当人死亡时,笔会发生什么? :) - Binkan Salaryman
显示剩余2条评论

26

关联(Association)指两个类之间存在某种关系,可以是任何类型的关系。

组合(Composition)和聚合(Aggregation)是两种关联方式。最简单的区分它们的方法是考虑“关系的强度”,即在删除拥有者对象时会发生什么。

聚合中,被聚合的对象会继续存在。(比如订单与产品,产品会继续存在)。

组合中,被组合的对象随着拥有者的消亡而消亡。(比如段落与文档,段落将随着文档的销毁而消失)。

有人认为聚合是没有意义的,因为用一个没有填充的箭头(关联)和一个没有填充的菱形(聚合)连接两个类并没有太大的区别。这两种关系非常相似。但是带有填充菱形的线(组合)则非常不同。


2
正确性、聚合和组合是与所涉及对象的生命周期相关的区别。 - beluchin

13
这是一个非常有争议的问题。正如Martin在他回答中所解释的,订单聚合了产品,这可以被认为是正确的。Grady Booch在他的《面向对象分析与设计》中提供了一个类似于关联的例子-销售与该销售中的产品相关联,反之亦然。而销售不会聚合产品。因此,所有的例子都应该是特定领域的,因为从另一个角度来看,关联可能变得更加具体。另一个例子是使用段落构成文档。
所以,在这个领域里,一切都强烈依赖于上下文。这就是面向对象编程。
您可以尝试将您的知识应用到您即将设计的特定项目中。如果您还没有阅读过Grady Booch的书籍,我建议您阅读。自那时以来,许多书籍已经出版,但它仍然是面向对象编程的圣经。

5

UML组合、聚合和简单关联是语义概念,而不是编程概念。它们的含义可以理解为:

  • 组合:A由B组成;B是A的一部分,因此没有A就不存在B。
  • 聚合:A拥有B,B属于A。
  • 关联:A使用B,在某种给定的方式下,A与B相关联。

(组合和聚合是关联的特殊类型。)

在Java中,您可以以相同的方式实现所有这些内容。这是一个概念上的区别。


1
据我所知,当A使用B(或者A了解B)时,这是一种依赖关系。 - maks
嗯...但是上述所有内容不都引入了依赖关系吗?但你说得对,“A知道B”太模糊了,无法描述关联。如果我没记错的话,关联是对象之间的,而依赖是类之间的 - 如果我错了请纠正我。 - Kos
根据http://www.uml-diagrams.org/class-diagrams.html#dependency "依赖关系是一种有向关系,当某个元素或一组元素需要其他模型元素来进行规范或实现时使用。这意味着依赖元素的完整语义要么在语义上,要么在结构上都依赖于供应元素(s)"。据我所理解,依赖关系可以存在于类与类之间,也可以存在于对象与对象之间。 - maks
这个描述对我来说似乎是在类之间 - 类A的规范或实现在某种程度上依赖于类B。但它并没有明确指定类A的单个对象与类B的对象之间的关系方式 - 这就是关联的作用。至少这是我的解释。 :) - Kos
@Kos: 如果聚合具有明确的语义,它就是一种编程概念。用“语义”这个词作为不定义任何东西的借口是很差的风格(你并不是世界上唯一这样做的人)。 - reinierpost

2
关联是指类之间的任何关系,其中一个类的实例具有对另一个类的实例的字段引用。
组合是一种“更强”的关系,意味着一个实例(父类)“拥有”另一个实例(子类)。
聚合并没有除了作为关联之外的任何其他语义。
在此处查看更多信息:http://martinfowler.com/bliki/AggregationAndComposition.html 编辑:您可以向聚合符号添加一些特殊语义,例如“最多只能由一个父项拥有,但可能更改父项或成为孤儿。” 但是,这些扩展是您自己定义的,并且在我所知道的范围内并未在UML中定义。

0

关于哪个词是哪个词似乎存在一些争议。

这与对象之间的父子关系有关,以及在删除父对象时子对象会发生什么。

其中一种情况认为,子对象在父对象之外没有生命,因此当删除父对象时应该同时删除子对象。类似于外键和关系型数据库中的“DELETE CASCADE”。

另一种情况认为,子对象应该在父对象之外继续存在,因此当删除父对象时不应该删除子对象。

我将让其他人争论哪个词描述了每种情况。


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