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

Javascript 组合与多重继承有何不同?,javascript,ruby,oop,inheritance,computer-science,Javascript,Ruby,Oop,Inheritance,Computer Science,在某些情况下,提倡组合而不是继承。我看到这种情况在Ruby和Javascript社区中越来越多地发生 组合听起来很像多重继承。我甚至在一些Ruby实现内部读到,模块组合是带有少量语法糖分的多重继承 是同一件事吗?如果没有,它与多重继承有何不同?继承和组合在实现的方面是相似的,当你说组合时,你暗示了这一点 听起来很像多重继承 本代码示例说明了基本区别: 继承 class Fruit { ... } class Apple extends Fruit { ... } 作文 cla

在某些情况下,提倡组合而不是继承。我看到这种情况在Ruby和Javascript社区中越来越多地发生

组合听起来很像多重继承。我甚至在一些Ruby实现内部读到,模块组合是带有少量语法糖分的多重继承


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

继承和组合在实现的方面是相似的,当你说组合时,你暗示了这一点

听起来很像多重继承

本代码示例说明了基本区别:

继承

class Fruit {
    ...
}

class Apple extends Fruit {
    ...
}
作文

class Fruit {
    ...
}

class Apple {
    this.fruit = new Fruit();
}
设计选择的含义在这里应该是显而易见的:

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

另一方面,组合增加了子类与其父类之间的访问级别。这里的好处是,对“父”类的更改不太可能产生影响深远的副作用。这里的权衡是,它在一定程度上增加了复杂性

一个好的经验法则是考虑类的语义。想想这两个类之间的关系。如果你可以说
是一个
,那么使用继承;否则使用构图。在上面的例子中,我们可以说一个
苹果
是一个
水果
,所以继承在这里可能是有意义的。再说一次,这是一个建议,不是规则


查看更深入的解释。

这取决于“多重继承”和“组合”的含义。如果组合和继承都只是意味着添加到对象响应的消息列表中,那么它们在定义上是相等的

假设类只是方法的集合,语言中的每个对象都是通过对类和一些数据的引用来定义的。如果对象通过调用与其类关联的方法查找函数来响应消息,并且方法查找函数要么返回方法(如果该类包含与消息对应的方法),要么递归调用其超类上的方法查找函数,那么我们就有了一种单继承、无组合的语言。通过修改Ian Piumarta在的第2.2节中描述的方法查找函数,可以将多重继承添加到此类语言中。基本上,只需添加一个类,该类将方法查找延迟到多个其他类而不是一个。很容易看出,mixin/traits(我假设这就是你所说的合成)可以用完全相同的方式添加


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

很多人从技术角度谈论多重继承,但我想谈谈设计方面

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

1.

就像建议它使用高内聚模式一样,一个类不应该有太多的职责

2.

继承锁定您的体系结构。如果你想改变什么,你必须改变一切。我给你举一个例子:想象一些类,比如
car
truck
boat
plane
继承自类
motorVehicle
。现在,我添加了一个新概念:汽车、卡车、船和飞机也在移动车辆。我该怎么办

  • 使用多重继承?我的班级将承担许多责任(希望我的语言允许)
  • 为这个新概念使用构图?但是为什么汽车更像是机动车辆而不是机动车辆呢
  • 尝试将
    机动车辆
    机动车辆
    混合使用。我的班级将有两种不同的高度相关的职责,这真的很糟糕
如果我加一辆自行车呢!这就是为什么继承只能用于分解具有相同责任的类的代码

结论

class Fruit {
    ...
}

class Apple {
    this.fruit = new Fruit();
}
如果一个类应该只有一个明确标识的责任,并且您应该只对具有相同责任的类使用继承,那么在正确的OOP设计中永远不应该使用多重继承

我建议您始终使用带有接口的组合,以降低类之间的耦合。这将为您提供更具可伸缩性、可维护性和可测试性的代码

在上一个示例中,使用组合将导致一些电机类继承自电机接口,一些移动类继承自移动接口,以及类
car
truck
。。。将“使用”电机接口和移动接口。我们的
自行车
只能“使用”移动界面


继承在JS中并不是那么好,因为对象具有很强的可塑性,它们的方法具有很强的可重用性,而且迭代对象装饰(与内在继承相反)的“成本”已不再是过去的成本,或者至少还不足以超越其他编码关注点和开发友好模式