组合与多重继承有何不同?

13
对于某些情况,推荐使用组合(composition)而不是继承(inheritance)。我看到这在 Ruby 和 Javascript 社区中越来越普遍。
组合听起来很像多重继承。我甚至读到过,在一些 Ruby 实现内部,模块组合实际上就是带有轻微语法糖的多重继承。
它是相同的吗?如果不是,那么它与多重继承有什么不同?

在JS中,继承并不是那么好用,因为对象非常可塑,它们的方法非常适用,并且迭代对象装饰(与内在继承相比)的“成本”已经不像以前那样高了,或者至少不足以抵消其他编码问题和开发友好型模式的影响。 - dandavis
3个回答

6

这取决于您所指的“多继承”和“组合”的含义。如果组合和继承都只是向对象响应的消息列表中添加内容,那么它们在定义上是相等的。

假设类只是方法的虚拟表,每个语言中的对象都由对类的引用和一些数据定义。如果一个对象通过调用与其类关联的方法查找函数来响应消息,而该方法查找函数返回该方法(如果类包含与消息对应的方法)或递归调用其超类的方法查找函数,则我们拥有了带有单继承和无组合的语言。可以通过按照Open Extensible Object Models第2.2节所述修改方法查找函数实现在此语言中添加多重继承,由Ian Piumarta编写。基本上就是添加一个将方法查找延迟到多个其他类而不仅仅是一个类的类。可以很容易地看出,混入/特征(我假设这就是你所说的组合)可以以完全相同的方式添加。

然而,如果你所说的“组合”是指一个对象具有其他对象作为实例变量,那么使用它而不是多重继承是有很好的理由的:封装。如果可以在父对象上调用实例变量中的对象的某些方法,则这些方法在实例变量的对象上可能就没有意义了。

5

很多人以技术方式谈论多重继承,但我想谈论设计方面。

在良好的面向对象编程(OOP)设计中,不应该使用多重继承。为什么?

1.

GRASP patterns所建议的高内聚模式一样,一个类不应该有太多的责任。

2.

继承锁定了你的架构。如果你想要改变任何东西,你必须改变所有东西。我给你一个例子:想象一些类如cartruckboatplane继承自类motorVehicle。现在,我添加一个新概念:汽车、卡车、船和飞机也是运动车辆。我该怎么办?

  • 使用多重继承?我的类将有许多职责(希望我的语言允许)。
  • 为这个新概念使用组合?但是为什么汽车会更像motorVehicle而不是movingVehicle呢?
  • 尝试混合motorVehiclemovingVehicle。我的类将有两个不同但高度相关的职责,这真的很糟糕。

如果我添加一辆自行车会怎么样!这就是为什么继承应该只用于为具有相同责任的类因式分解代码!

结论

如果一个类应该只有一个明确定义的职责,并且您应该仅将继承用于具有相同职责的类,则在正确的OOP设计中永远不应使用多重继承。

我建议您始终使用接口的组合来使您的类之间的耦合度低。这将为您提供更可扩展,可维护和可测试的代码!

在前面的例子中,使用组合将导致一些电机类继承自电机接口,一些移动类继承自移动接口,而类“car”、“truck”等将“使用”电机接口和移动接口。而我们的“bicycle”只能使用移动接口!

3
继承和组合在实现上有相似之处,你在提到组合时也暗示了这一点。但它们的根本区别可以通过以下代码示例来说明: 继承
class Fruit {
    ...
}

class Apple extends Fruit {
    ...
}

组成

class Fruit {
    ...
}

class Apple {
    this.fruit = new Fruit();
}

设计选择的含义应该是显而易见的:
继承使您能够轻松更新子类共享的功能,并帮助建立逻辑层次结构。然而,超类通常被认为是不稳定的,因为对超类的更改可能会产生非常广泛的副作用,您几乎需要不断地意识到这一点。
另一方面,组合在子类和其父类之间添加了一层访问级别。好处在于对“父”类的更改很少会产生需要关注的广泛副作用。这里的权衡是增加了一定程度的复杂性。
一个好的经验法则是考虑类的语义。考虑两个类之间的关系。如果您可以说child是一个parent,那么使用继承;否则使用组合。在上面的示例中,我们可以说Apple是一个Fruit,因此在这里使用继承可能是有意义的。再次强调,这只是一个建议,而不是规则!

请查看这篇文章,以获得更深入的解释。


我认为你这里的组合定义与 OP 的不同,我认为 OP 在这里谈论的是组合概念:https://medium.com/javascript-scene/3-different-kinds-of-prototypal-inheritance-es6-edition-32d777fa16c9 - Norman Xu

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