为什么更喜欢组合而不是继承?每种方法都有哪些权衡?什么时候应该选择继承而不是组合?
当前回答
我同意@帕维尔的说法,他说,有地方可以组成,也有地方可以继承。
我认为如果你的答案是肯定的,那么应该使用继承。
您的类是从多态性中受益的结构的一部分吗?例如,如果您有一个Shape类,它声明了一个名为draw()的方法,那么我们显然需要Circle和Square类作为Shape的子类,这样它们的客户端类将依赖于Shape而不是特定的子类。您的类是否需要重用其他类中定义的任何高级交互?如果没有继承,模板方法设计模式将不可能实现。我相信所有可扩展框架都使用这种模式。
然而,如果您的意图纯粹是代码重用,那么组合很可能是更好的设计选择。
其他回答
继承是非常强大的,但你不能强迫它(参见:圆-椭圆问题)。如果你真的不能完全确定一个真正的“is-a”子类型关系,那么最好是组合。
你想强迫自己(或其他程序员)坚持什么,什么时候你想让自己(或另一个程序员)有更多的自由。有人认为,当你想强迫某人以某种方式处理/解决某个特定问题时,继承是有帮助的,这样他们就不会走错方向。
Is-a和Has-a是一个有用的经验法则。
在可以枚举不变量的情况下,子类型更合适,功能更强大,否则使用函数组合实现可扩展性。
我看没有人提到钻石问题,这可能是继承带来的。
总之,如果类B和C继承了a,并且都重写了方法X,而第四个类D继承了B和C,并且没有重写X,那么应该使用X D的哪个实现?
维基百科对这个问题中讨论的主题提供了一个很好的概述。
继承带来了所有不可否认的好处,下面是它的一些缺点。
继承的缺点:
您不能在运行时更改从超级类继承的实现(显然是因为继承是在编译时定义的)。继承将子类暴露给其父类实现的细节,这就是为什么人们常说继承破坏了封装(从某种意义上讲,您真正需要关注的是接口而不是实现,所以通过子类重用并不总是首选的)。继承提供的紧密耦合使得子类的实现与超级类的实现紧密结合,父类实现中的任何更改都将迫使子类进行更改。子类的过度重用会使继承堆栈变得很深,也很混乱。
另一方面,通过对象获取对其他对象的引用,在运行时定义对象组合。在这种情况下,这些对象将永远无法访问彼此的受保护数据(没有封装中断),并将被迫尊重彼此的接口。在这种情况下,实现依赖性也会比继承的情况下少得多。