关于如何在面向对象的系统中最好地扩展,增强和重用代码,有两种思路:
继承:通过创建子类来扩展类的功能.覆盖子类中的超类成员以提供新功能.当超类想要一个特定的接口但是对它的实现不可知时,使方法抽象/虚拟以强制子类"填空".
聚合:通过获取其他类并将它们组合到一个新类中来创建新功能.为这个新类附加一个公共接口,以便与其他代码进行互操作.
每个的好处,成本和后果是什么?还有其他选择吗?
我看到这个辩论定期出现,但我认为它还没有被问到Stack Overflow(虽然有一些相关的讨论).谷歌的结果也令人惊讶地缺乏.
我知道之前已经讨论过这个问题,但似乎总是假设继承至少有时候比组合更好.我想挑战这个假设,希望获得一些理解.
我的问题是:既然你可以完成与对象组合东西,你可以用经典的继承和自经典的继承是很经常被滥用[1] ,自对象组合为您提供了灵活地改变委托对象运行时,为什么你会永远使用经典继承?
我可以理解为什么你会推荐Java和C++等语言中的继承,这些语言不能提供方便的委派语法.在这些语言中,只要不明显不正确,就可以使用继承来节省大量的输入.但是像Objective C和Ruby这样的其他语言提供了经典的继承和非常方便的委托语法.Go编程语言是我所知道的唯一一种语言,它认为经典继承比它的价值更麻烦,并且仅支持代码重用的委托.
陈述我的问题的另一种方式是:即使您知道经典继承对于实现某个模型不是不正确的,那么这个理由是否足以使用它而不是组合?
[1]许多人使用经典继承来实现多态,而不是让他们的类实现接口.继承的目的是代码重用,而不是多态.此外,有些人使用继承来模拟他们对"is-a"关系的直观理解,这种关系往往是有问题的.
更新
我只想在谈到继承时澄清我的意思:
我在谈论一种继承的类型,即一个类继承自部分或完全实现的基类.我不是在谈论继承纯粹抽象的基类,这与实现接口相同,我记录的并不反对.
更新2
我知道继承是实现C++多态性的唯一方法.在这种情况下,显而易见的是你必须使用它.所以我的问题仅限于Java或Ruby等语言,这些语言提供了实现多态的不同方法(分别是接口和鸭子类型).