UML关联与组合以及细节级别

20
事实上,这是几个关于UML的业余问题!当创建一个UML图以对一些领域概念进行建模时,如果遇到一个包含有关另一个概念信息的领域概念,是更好地在模型本身中持有该实体的标记/引用,还是持有整个实体?请记住,这涉及创建一个简单的高级模型 - 我相信在实现阶段事情会略有不同。
例如,下面两个模型中哪一个才是正确的?第一个具有组合关系,FlightBooking持有整个Flight。而第二个,FlightBooking只是持有Flight的引用。

http://imageshack.us/m/96/2227/flightiu.png

其次,在创建高级UML图模型领域概念时,你真正需要多少细节?例如,在下面的图表中,一个航班可以保存关于起点/终点的字符串,或者我可以为这些概念建立单独的类并创建组合关系。哪种方法更可取?

http://imageshack.us/m/23/3395/flight2s.png

此外,还有一件事,当对上述情况进行建模时,航班将起始地/目的地作为另一个类而不是字符串进行“持有”,这两种建模方式哪种是正确的?我很困惑何时显示关联和何时显示组合。
4个回答

19

关联(Association):
指两个类之间存在某种关系,可以是任何类型的关系。
例如:A使用B,A与B有一定的关系。

组合(Composition):
这也是一种特殊的关联类型,用于模拟“所有权”。它与聚合非常相似,唯一的区别在于它描述了整体-部分的关系,并且“部分”实体没有自己独立的存在。

例如:A由B组成;B是A的一部分,因此不能没有A而存在。

好的解释: UML类图:关联、聚合和组合


这个也有很好的解释:https://www.visual-paradigm.com/guide/uml-unified-modeling-language/uml-aggregation-vs-composition/ - shabby

1

如果您正在尝试对领域概念进行建模,那我建议您忘记组合/聚合,而是坚持使用简单的关联。为什么?因为决定组合/聚合会妨碍重要问题的解答。这些问题是:

  1. 为什么存在这种关系?具体而言,它捕获了哪些领域规则/约束条件?
  2. 每一端的基数是多少?
  3. 创建和删除行为是什么?即谁创建/删除关联实例?

关系命名 通过为关系端点命名来实现(1)。不使用角色名称(例如您第一个示例中的“航班”),因为这并不能告诉您关系存在的原因。因此,在您的示例1中:该关系代表什么?是航班上的预留座位吗?确认的座位?已付款?从图表中无法确定。有各种基于动词的命名方法,请参见this post。为什么要这样做?因为它促使您确保了解领域。大部分(可能是大多数,尽管我从未证明过)领域规则存在于关系中。因此,了解关系存在的原因对于理解领域至关重要。

基数 比名称更明显。您应该在两端确定 - 上限和下限。在下限方面,重要的是确定是否可选(即0或1)。在上限方面,是1还是多个。同样,这会从领域中浮现出重要的规则。回到您的示例:一个航班预订中有多少个航班?一个航班可以在多个预订中吗?(无论“在”意味着什么...)。

创建/删除行为 谁创建关系的实例?谁删除?如果其中一端被删除,另一端会发生什么?同样,所有来自问题领域的重要规则。

这些答案也希望回答了您的第二个问题。不要省略关系。花时间去理解它们。它们是理解领域的秘密酱汁。回答上述所有问题将为您提供比尝试在组合/聚合/关联之间做出决定更深入的见解。

如果您真的想展示组合与关联,那么只需回答上述问题即可。

如果关系的一端的基数是1:1(即只能有一个),并且该端负责创建和删除另一端的实例,则可以将其表示为组合。否则,请使用简单的关联。至于聚合:请忽略它。从价值上讲,它会引起更多的混乱。您可以通过正确定义的简单关联更清晰、更精确地表达聚合所能表达的所有内容。希望对您有所帮助。PS:语法要点:组合使用填充的菱形。您展示的是聚合。

1
组合、聚合和关联。
  • 首先你应该了解A到B的关联是什么。基本上它是A和B之间的实线。它可以表示连接A类/实例和B类/实例的一种结构。这个结构可以是任何类型并属于任何地方。写在这条线上的所有信息都描述了这个结构。
  • 如果有两个结构,一个连接A的一个实例与B的实例,另一个连接B的一个实例与A的实例,你可以在一个关联中同时展示它们。然后,关于B端的信息描述第一个结构(b->a),而关于另一个端的信息描述另一个结构。
  • 如果从A到B有多个结构引导,你必须绘制两个不同的关联。
  • 如果连接结构很复杂,你可以将它表示为关联类。在那里你可以定义更多细节。
  • 连接结构可以连接多于两个类,那么它将显示为一个大菱形,其实线分支到这些类。它仍然是关联!注意:这两个更复杂的关联在现有工具中支持得非常糟糕。你可以很容易地创建一些绝对没有意义的东西。而且它们很难使用。请小心使用。
  • 在C++中,实例A可以直接拥有B实例,而不是通过指针。没有特殊的UML符号,它应该以与普通指针属性相同的方式显示。

example Class diagram


  • 所谓的黑色或实心菱形表示组合关系,位于容器一侧。
  • 另一个空心菱形称为“共享聚合”,简称“共享”,没有严格的定义,您可以使用它创建自己的标准。当然,在项目-容器关联的项目侧上放置它是愚蠢的。但它很容易位于关联的两端。
    • 为什么组合关系只能在一侧?因为组合意味着,只有从容器(或容器本身)引用它们时,项目才存在。当然,这对双方都不起作用。
    • 相反,“共享”在两侧经常有意义。例如,学生实例可以具有所有课程的列表,而课程实例可以具有所有参加学生的列表。
  • 通常可以看到“聚合”一词用于“共享聚合”。这是一个错误。因为根据标准,组合共享甚至,这三个都是聚合。
因此,组合聚合的子集,聚合关联的一种特性。

我不同意一个关联的两端都可以表示共享聚合的观点。聚合通常被理解为(即在字典中定义)聚合项是聚合器的“一部分”。参加的课程不是学生的一部分。在整个OMG UML标准中,你不会看到两端都有开放菱形的关联。同样,你也不能使用像MagicDraw这样的工具创建这样的结构。 - Huliax
@Huliax 是的,UML标准明确禁止双向共享聚合。没有任何理由。而且一些工具也可能禁止它(VP和MS Studio允许它)。您的例子是正确的,但这并不证明不存在其他例子,其中它是有用的。想象一下类CatMale和CatFemale,每个类都有一个性伴侣列表,雄性为雌性提供,反之亦然。 - Gangnus
@Gagnus。培育伙伴关系只是普通的合作关系。它们无法通过“部分”的测试。 - Huliax
@Huliax 共享聚合并不意味着“部分”。它甚至没有“元素”的含义。它的含义是:“部分的元素”。而这个元素可以仅仅是对元素的引用。拥有关于某物的信息(拥有引用意味着拥有信息)并不一定意味着拥有某物作为一部分。 - Gangnus
我不同意Gagnus的观点。我更或多或少同意@sgokhales回答中发现的链接中所述的内容。 - Huliax
@Huliax 1. 为什么你用第三人称称呼我?2. Gangnus。3. 所以,你无法捍卫你的论点,你没有任何反驳我的论据,但你不同意。这是你的权利 :-). - Gangnus

0

对于您的第一个例子,使用组合的第一张图是正确的。您的第二个选项,将flightID作为int引用,可能可以工作,但它是不完整的:仅凭该int无法让您访问Flight对象。Flight类并没有神奇地存储可以按编号检索的航班对象列表,因此第二个选项需要在某个地方存储所有Flight对象的第三个类。

对于您的第二个问题,在高层次上,这实际上取决于个人喜好(或您教授的个人喜好!)。只需尽力做出最佳判断即可。


这个答案完全是错的。首先,第一个图示并不展示组合,而是共享聚合。如果它是组合关系,那么如果航班预订不存在,航班也将不存在,这根本就没有任何意义。 - Huliax
1
回顾5年前的这个答案,你是对的,它在几个方面都是错误的。我不记得写过它,所以我的结论是当时我一定是喝醉了。 - Username Obfuscation

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