组合如何不同于多重继承?

时间:2014-12-19 19:43:45

标签: javascript ruby oop inheritance computer-science

对于某些情况,提倡构成而不是继承。我在Ruby和Javascript社区中看到这种情况越来越多。

听起来很像多重继承。我甚至在一些Ruby实现中内部读过,模块组合是多重继承,具有较小的语法糖。

这是一回事吗?如果没有,它与多重继承有何不同?

3 个答案:

答案 0 :(得分:3)

继承和组合在它们可以实现的目标上是相似的,当你说这个组合时你暗示了这一点

  

听起来很像多重继承

这个代码示例可以说明根本区别:

<强>继承

class Fruit {
    ...
}

class Apple extends Fruit {
    ...
}

<强>组合物

class Fruit {
    ...
}

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

设计选择的含义应该在这里显而易见:

继承为您提供了额外的好处,即使您的子类共享的功能非常容易更新,并有助于为您的类建立逻辑层次结构。然而,超类通常被认为是不稳定的,因为对超类的改变可能会产生非常深远的副作用,你需要几乎不断地意识到这一点。

另一方面,

组合会在子类及其父级之间添加一定级别的访问权限。这里的好处是改变了父母&#34;班级不太可能产生影响深远的副作用。这里的权衡是它在一定程度上增加了复杂性。

一个好的经验法则是考虑类的语义。想想两个班级之间的关系。如果您可以说child parent,那么请使用继承;否则使用组合。在上面的示例中,我们可以说AppleFruit,因此继承可能在这里有意义。同样,这是一个建议,而不是规则!

查看this article以获得更深入的解释。

答案 1 :(得分:3)

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

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

<强> 1

就像GRASP patterns建议它具有高凝聚力模式一样,一个班级不应该有很多责任。

<强> 2

继承锁定您的体系结构。如果你想改变任何东西,你必须改变一切。我举个例子:想象一下从car继承的truckboatplanemotorVehicle等类。现在,我添加了一个新的概念:汽车,卡车,船和飞机也在移动车辆。我该怎么办?

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

如果我加一辆自行车怎么办?这就是为什么继承只应用于对具有相同责任性的类的代码进行分解的原因!

<强>结论

如果一个类应该只有一个明确标识的责任,并且你只应该对具有相同责任的类使用继承,那么你就不应该在正确的OOP设计中使用多重继承。

我建议你总是使用带接口的合成来实现类之间的低耦合。这将为您提供更具可扩展性,可维护性和可测试性的代码!

  

在前面的示例中,使用合成将导致某些运动类继承自电机界面,一些移动类继承自移动界面,类cartruck,...将“使用”电机接口和移动界面。我们的bicycle将只能“使用”移动界面!

答案 2 :(得分:1)

这取决于你的意思&#34;多重继承&#34;和&#34;组成。&#34;如果组合和继承只是意味着添加到对象响应的消息列表,那么它们在定义上是相同的。

让我们说类只是virtual tables方法,并且语言中的每个对象都是通过对类和某些数据的引用来定义的。如果一个对象通过调用与它相关联的方法查找函数来响应消息,并且方法查找函数要么返回该方法(如果该类包含对应于该消息的方法),要么递归调用方法查找函数在它的超类中,我们有一种具有单一继承且没有组合的语言。通过修改Ian Piumarta的Open Extensible Object Models第2.2节中描述的方法查找功能,可以添加多重继承这样的语言。基本上,只需添加一个类,将方法查找推迟到多个其他类而不是一个。很容易看出mixins / traits(我假设这是你的意思是组合)可以完全相同的方式添加。

然而,如果通过&#34;组合&#34;你的意思是一个对象有其他对象作为实例变量,那么有一个很好的理由使用它而不是多重继承:封装。如果可以在父对象上调用实例变量中的对象,那么它们就没有意义。