将关联、聚合和组合转换为Java代码?

7

我知道在Java中,关联、聚合和组合的转换有不同的表示方式。但是当我们将它们转换成代码(Java类)时,它们都以相同的方式表示。比如,学生由老师教授,这是一种关联关系,将用具有Class Teacher实例变量的Student类来表示。

部门有教授,这是一种聚合关系,也将用具有Class Professors实例变量(数组)的Department类来表示。

大学有部门,这是一种组合关系,同样会使用具有Class department实例变量(数组)的University类来表示。

因此,在代码方面,它们都以相同的方式表示。那么关联、聚合和组合术语对开发者有什么好处呢?

1个回答

5
您在组合中缺少一部分内容。它需要几个额外的属性:
  • 父级不可变性(即子级无法切换父级)
  • 子级的生命周期责任由父级负责。即父级负责创建和删除子实例。子实例不能在父级死亡后继续存在。
您是正确的,关联将在子级和父级中表现为引用/引用集合。但是,如果代码要确保强制执行组合语义,则还必须执行上述规则。
至于聚合:我不使用它。语义太松散了,与直接关联相比没有任何优势。
希望有所帮助。

抱歉,sfinnie,我错过了两个要点。 要点1:- 如果我们考虑原始帖子中的组合示例,您是否在说University类应该具有Class department的实例变量(数组)作为final。如果不是,我们将如何在代码中表示它。 要点2:- 是的,我同意您的观点,但是当我们将uml图转换为编码时并没有什么区别,因为它仍然是一个简单的实例变量。 - M Sach
点1:是的。点2:这不仅仅涉及到引用。UML组合语义要求“如果删除一个组合,则通常会将其所有部分一起删除”(UML超结构2.3,第40页)。在像C++这样的非GC语言中,这意味着析构函数代码必须确保在删除父对象之前删除所有子对象。对于GC环境来说,这并不明显。然而,有些惯用法——例如领域驱动设计所推广的“聚合根”方法——只能通过父对象本身的方法来创建(或删除)子对象...(续). - sfinnie
因此,在原型订单/订单行的情况下,唯一从订单中添加订单行的方法是调用Order.AddOrderLine()(删除同理)。因此,总结一下:在代码中没有直接的声明性模拟复合体的方式。相反,您必须逐步构建行为。因此,在代码中识别组合需要有一定的“模式识别”能力。如果引用是最终的,并且创建/删除子项的唯一方法是通过父项的接口,则该关系可能是复合关系。希望对你有所帮助。 - sfinnie
感谢sfinnie提供如此精彩的解释。我想再补充一点。正如你所说,子对象在父对象死亡后无法继续存在,并用GC术语进行了解释。这是一个很好的观点。但是我们是否也可以在组合中说,如果我们想要从数据库中删除大学,首先必须从数据库中删除部门。这在某种程度上有助于开发人员理解不同实体之间的行为。 - M Sach
@Mohit:基本上是这样的。关系型数据库确实有一个声明性的习惯用语:在DDL中,您添加一个“ON CASCADE DELETE”约束。它表示如果删除父项,则必须删除子项。但是,如果您无法直接控制DDL,则您是正确的,代码必须确保在删除父项时删除所有子项。希望对您有所帮助-感谢您的友善评论。 - sfinnie

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