组合与继承

3

对于UML类图,如果一个类A与另一个类B存在组合关系,那么它是否像继承一样工作?我知道类A不能没有类B,但是类A是否会继承类B的属性和方法?

3个回答

11

组合优于继承

在面向对象设计中,常见的建议是优先选择组合而非继承。这可能会让人误以为这两个不同的概念之间存在关系:

  • 继承是关于类之间的关系。
  • 组合是关于类的对象之间的关系。

更加误导的是,通用的OO文献中所使用的“组合”通常对应于简单的UML关联,并且不能像UML“组合”那样被理解为具有限制性。

继承是关于泛化和特化的

如果类DB继承,这意味着D特化了一个更一般的概念B

  • 它具有B的所有属性和操作(无需在图表中重复),
  • 它可以具有对B不相关的其他属性和操作,
  • 它可以以不同的方式执行B的一些操作。
  • D的任何对象在其整个生命周期中也是类B的对象。这就是为什么我们谈论“是一个”关系的原因。

天真的例子(仅用于说明):

enter image description here

组合是关于非常不同类的对象之间的关联

如果类BC“组合”(具有组合关联),这意味着B对象可以在其生命周期内与不同的C对象相关联。并且类C的对象:

  • 总是属于拥有它的B对象。这就是为什么我们有时会说“拥有”关系;
  • 将不会存活于拥有它的B对象。

注意:UML组合是关于独占所有权的。在OO文献中,“组合”一词通常指没有任何所有权甚至排他性的较弱关联。

天真的例子(仅用于说明):

enter image description here


1
即使你的答案质量很好,我还是有几点意见。关于引擎和轮子的组合确实不是一个好选择,我们都知道汽车可以被摧毁,但其中一些部件仍然幸存,包括引擎和轮子。而且现在越来越多的混合动力汽车都配备了多个引擎,包括电动引擎,所以单一性已经过时了^^,你可以添加HybridCar继承ElectricalCarGazolineCar。最后,我知道有些汽车包括旧款汽车只有3个轮子(第五个可能是用来替换其中之一的)。 - bruno
有趣的是,下面的图表经常出现一个缺陷。你的类 Car 实际上是 Chassis,而只有整个结构才能被称为 Car。UML 对于展示这种结构的存在性实际上很差,经常导致混淆(关于聚合的问题)。 - qwerty_so
@qwerty_so 这就是我在对Bruno的第一条评论中试图解释的内容:在现实生活中,对于真实的汽车,我个人会选择复合材料或ECS。然而,在许多情况下,这种简化和天真的模型已经足够了,例如在线汽车配置器或交通仿真(例如,如果电动汽车达到20%并且交通信号灯阻止一些频繁使用的街道,可以找出对城市CO2排放的影响)。因此,如果符合目的,UML允许以不同寻常的方式对这种简化的现实进行建模,这是一件好事;-) - Christophe
2
这就是我们回到爱因斯坦的地方:尽可能简单,但不要过于简单。可能会引发漫长的讨论 :-) - qwerty_so
非常感谢大家的帮助! - Binaya Thapa Magar
显示剩余3条评论

0
继承和组合是两个不同的概念。如果它们是相同的,就不需要有不同的表示方法了。
组合关注对象的生命周期。组合的元素将在拥有者被销毁时同时被销毁。但每个实例可以(而且很可能)与组合对象完全不同。一个众所周知的例子是汽车:当你把一辆汽车撕碎时,它的组成部分——轮子也会被撕碎。只有在事先分离它们之后,它们才能继续存在。
继承意味着实例将具有在父类中定义的自己的操作和属性。这适用于每个单独的实例。对于继承来说,没有好的现实世界的例子(基因的工作方式不同,继承的资产也无法帮助解释)。

感谢您的解释。 - Binaya Thapa Magar
请考虑在Christophe的答案上打上“正确”的勾,因为他的回答比我的更详细。(他似乎比我有更多时间;-)) - qwerty_so
完成了!对于这次的迟更,非常抱歉。 - Binaya Thapa Magar

0
如果类A与另一个类B存在合成关系
假设你的意思是A <>--- B或A <>---> B,而不是反过来(B <>--- A或B <>---> A),因为在你的问题中并不是很清楚。
类A不能没有类B存在。
这与"类"无关,而是关于这些类的"实例",B可以独立于该合成拥有实例,因此有限寿命并不适用于B的所有实例。
它不像继承那样工作。类A不会继承类B的属性和方法。

A继承B意味着A是一个B,这绝对不适用于A <*>--- B或者A <*>---> B或者反过来。

然后,无论操作的可见性如何,您都不能将A的操作应用于B的实例,反之亦然,除非您还有一个比组合更高的继承。

关于B的属性,根据组合的实现方式,它们可能是相应A实例的一部分,例如在C++中不使用指针进行组合时就是这种情况。但无论如何,这并不意味着B的这些属性是A的属性,要访问它们,首先需要通过组合访问B的实例,并且这也假设A的实例有权直接访问B的这些属性,因此它们通常是public的。

请注意,你可以拥有 A<*>--->B<*>--->A 等等,幸运的是这意味着 A 继承了 B,而 B 继承了 A,这是不可能的。

谢谢解释 - Binaya Thapa Magar

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