我知道之前已经讨论过这个问题,但似乎总是假设继承至少有时候比组合更好.我想挑战这个假设,希望获得一些理解.
我的问题是:既然你可以完成与对象组合东西,你可以用经典的继承和自经典的继承是很经常被滥用[1] ,自对象组合为您提供了灵活地改变委托对象运行时,为什么你会永远使用经典继承?
我可以理解为什么你会推荐Java和C++等语言中的继承,这些语言不能提供方便的委派语法.在这些语言中,只要不明显不正确,就可以使用继承来节省大量的输入.但是像Objective C和Ruby这样的其他语言提供了经典的继承和非常方便的委托语法.Go编程语言是我所知道的唯一一种语言,它认为经典继承比它的价值更麻烦,并且仅支持代码重用的委托.
陈述我的问题的另一种方式是:即使您知道经典继承对于实现某个模型不是不正确的,那么这个理由是否足以使用它而不是组合?
[1]许多人使用经典继承来实现多态,而不是让他们的类实现接口.继承的目的是代码重用,而不是多态.此外,有些人使用继承来模拟他们对"is-a"关系的直观理解,这种关系往往是有问题的.
更新
我只想在谈到继承时澄清我的意思:
我在谈论一种继承的类型,即一个类继承自部分或完全实现的基类.我不是在谈论继承纯粹抽象的基类,这与实现接口相同,我记录的并不反对.
更新2
我知道继承是实现C++多态性的唯一方法.在这种情况下,显而易见的是你必须使用它.所以我的问题仅限于Java或Ruby等语言,这些语言提供了实现多态的不同方法(分别是接口和鸭子类型).
为什么我们构建原型继承链而不是使用对象组合.通过原型查看链中的每个步骤都很昂贵.
这是一些虚拟示例代码:
var lower = {
"foo": "bar"
};
var upper = {
"bar": "foo"
};
var chained = Object.create(lower, pd(upper));
var chainedPrototype = Object.create(chained);
var combinedPrototype = Object.create(pd.merge(lower, upper));
var o1 = Object.create(chainedPrototypes);
var o2 = Object.create(combinedPrototypes);
Run Code Online (Sandbox Code Playgroud)
使用,pd因为属性描述符是冗长的地狱.
o2.foo比较快,o1.foo因为它只上升了两个原型链而不是三个.
由于在原型链上行进是昂贵的,为什么我们构造一个而不是使用对象组合?
另一个更好的例子是:
var Element = {
// Element methods
}
var Node = {
// Node methods
}
var setUpChain = Object.create(Element, pd(Node));
var chained = Object.create(setUpChain);
var combined = Object.create(pd.merge(Node, Element));
document.createChainedElement = …Run Code Online (Sandbox Code Playgroud)