“继承是否应该避免”的想法源自哪里?

时间:2011-02-09 14:04:29

标签: design-patterns language-agnostic inheritance

最近我们讨论了一个缺陷mentioned here,其中一方表示“是的,这就是为什么书籍应该避免继承。”

我多年来一直在使用继承,并且在许多设计案例中发现它非常有用和方便。此外,我确信这个人至少会误解这些“书说”的内容。

真的有一个想法,继承有点坏,应该避免吗?它来自哪里,我在哪里可以了解更多?

5 个答案:

答案 0 :(得分:9)

我认为他的意思是继承可能被过度使用,即使在组合是更好的解决方案的情况下也是如此。这在几本书中讨论过,例如

  

继承是实现代码重用的有效方法,但并不总是最好的   工作的工具。使用不当,会导致软件脆弱。使用安全   包内的继承,子类和超类的实现   是在同一个程序员的控制下。使用继承也是安全的   扩展专门为扩展而设计和记录的类   (第17项)。从包边界继承普通的具体类,   但是,这很危险。提醒一下,本书使用“继承”一词来表示   意味着实现继承(当一个类扩展另一个类时)。问题   本项中讨论的不适用于接口继承(当类实现时)   一个接口或一个接口扩展另一个接口)。

     

与方法调用不同,继承违反了封装 [Snyder86]。   换句话说,子类依赖于其超类的实现细节   因为它的正常功能。超类的实现可能会从发布中改变   要释放,如果确实如此,子类可能会中断,即使它的代码没有   被感动了。因此,子类必须与其超类一起发展,   除非超类的作者专门设计并记录了它   为了扩展目的。

  • Effective C++ 3rd Edition有几个与此相关的项目:
    • 第32项:确保公共继承模型“是-a。”
    • 第34项:区分接口的继承和实现的继承
    • 第38项:模式“has-a”或“is-implemented-in-terms-of”通过作文

答案 1 :(得分:3)

每次都不应该避免,但是当你遇到来自超类的一组定义的操作时,它会阻碍灵活性。基本的设计理念是“留下继承固定部件并注入可能发生变化的部件”。

Head First Desing Patterns中有一个很好的例子。

假设您决定使用实现fly()的基类来建模ducks。假设你有一个不能飞的RubberDuck,当然。使用不执行任何操作的方法覆盖fly()。但是有一天你添加了DecoyDuck而忘记覆盖fly()并且你弄得一团糟。最好是构建注入所需行为的DecoyDuck(组合而不是继承)。

答案 2 :(得分:2)

C ++中的良好编码实践更喜欢通过聚合进行组合。比照"C++ Coding Standards: 101 Rules, Guidelines, And Best Practices" by Sutter/Alexandrescu

答案 3 :(得分:2)

不应该“按原样”避免继承 当您想要定义/描述'是'关系时,应该使用(并且仅使用)继承。

当一个实体'不是'非连贯性时,实体不应该从连贯性继承。 在这种情况下,应该使用组合物。

答案 4 :(得分:2)

继承有助于泛化(在OOP术语中向上转换),而Composition有助于行为定义(控制反转 - 或依赖注入)。

应该使用任何一种获得更多利益的方式;但赞成Composition也使代码更具扩展性。因此,代码变得“不接受修改,但对扩展开放”,因此“HAS-A优于IS-A”。

有点像自己开车还是拥有一辆车(或不是?)