赞成合成而不是继承
是非常受欢迎的短语。我读过几篇文章,最后每篇文章都说
当类之间存在纯粹的IS-A关系时使用继承。
来自this article的示例:
在 Apple 和 Fruit 之间存在明显的IS-A关系,即Apple IS-A Fruit,但作者还将其显示为Apple HAS-A Fruit(组合)以显示使用继承实现时的陷阱。
我在这里有点困惑,声明是什么意思
当类之间存在纯粹的IS-A关系时使用继承。
使用合成而不是继承意味着总是尝试来应用合成,即使存在纯粹的IS-A关系,并且只为那些情况下保留继承作文没有意义?
答案 0 :(得分:73)
当您使用继承来重用超类中的代码,而不是覆盖方法并定义另一种多态行为时,通常表明您应该使用组合而不是继承。
java.util.Properties
类是继承使用不当的一个很好的例子。它不是使用 Hashtable来存储其属性,而是扩展 Hashtable,以便重用其方法并避免使用委托重新实现其中的一些。
答案 1 :(得分:6)
我认为这是面向对象设计中讨论最多的一点。正如文章中所建议的,组合总是优于继承。这并不意味着你永远不应该使用继承。你应该在哪里更有意义(哪些可以辩论)。
使用合成有许多优点,其中几个是:
答案 2 :(得分:4)
我想一个好的指导方针是:
当存在IS-A关系时,请使用继承。否则,请使用 组合物。
其原因与面向对象设计中的另一个概念 - 多态性有关。多态性是许多OOP语言的一个特性,其中一个对象可以用来代替另一个对象,只要第一个类是第二个类的子类。
为了说明,想象一下,如果你有一个接受一种动物的功能。使用继承时,只有一个函数:
void feed( Animal a );
多态性向我们保证,我们接受的任何动物亚类都将被接受。否则,我们将被迫为每种类型编写一个函数。我认为这样做的好处超过了它的缺点(例如减少封装)。
如果没有IS-A关系,我认为多态性不会很有效。因此,最好使用组合并在类之间增强封装/隔离。
答案 3 :(得分:3)
在文章中,没有这样的短语:
use inheritance when there is pure IS-A relationship between classes
此外,谷歌除了你的帖子外没有在其他地方找到它。
相反,文章写道:
Make sure inheritance models the is-a relationship.
My main guiding philosophy is that inheritance should be used only when a subclass is-a superclass. In the example above, an Apple likely is-a Fruit, so I would be inclined to use inheritance.
这意味着,如果存在IS_A关系,请先尝试使用继承,而不是使用组合。并且没有using composition over inheritance
的偏好 - 每个都有利于自己的角色。
答案 4 :(得分:3)
此外,我想补充说Decorator pattern是一个示例,您可以使用组合而不是继承并动态地向对象添加职责。有效Java中的Decorator模式示例在“赞成组合而不是继承”项中提到。以Java API为例; BufferedReader修饰了一个Reader(而不是扩展FileReader,PipedReader,FilterReader等),因此可以装饰任何类型的Reader。缓冲功能在运行时附加到这些读取器,这是Decorator模式。
这里通过子类化进行扩展是不切实际的。
答案 5 :(得分:2)
当关系是永久关系时使用继承。不要仅仅为了获得自由行为而使用扩展。这就是他们在IS-A示例中所指的内容。仅在扩展类确实是父类的扩展时才扩展。有时它不会切割和干燥,但总的来说。如果您需要从“正确”类扩展,组合在未来也会提供灵活性。
这是关于扩展的一篇古老但很棒的文章:
http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html
答案 6 :(得分:0)
我会说不。在水果/苹果场景中,使用继承是很有意义的。该文章的作者也证实了这一点:“在上面的例子中,Apple很可能是一个水果,所以我倾向于使用继承”。
如果您的子类显然是超类,则继承很好。但在实践中,您会发现使用合成可以更好地解决更多情况。