何时防止类继承?

时间:2012-05-05 17:45:41

标签: oop inheritance

我最近被告知面向对象编程的一个好习惯,你应该总是允许继承你的类。我真的不这么认为,但我没有坚定的理由。

真实世界阻止继承的示例

  1. 没有C ++ STL类(专用类模板)允许继承(具有非虚拟析构函数)。
  2. Java的final类修饰符适用于许多标准组件,例如java.lang.String
  3. 可能的原因我认为:

    1. 安全性,因为子类可能有权访问敏感的内部。 (我不这么认为 - 他们不会访问私人会员。)
    2. 性能,因为子类可能会通过覆盖某些成员函数来破坏我们的高效实现。 (儿童不会覆盖非虚拟功能。)
    3. 强制执行合成而不是继承。 (我完全同意。如果不需要,我们不应该赞成继承。)
    4. 所以我的问题是:我应该在什么情况下故意阻止继承?

3 个答案:

答案 0 :(得分:4)

对于初学者来说,如果你是积极的,那么只允许继承你不希望别人扩展你的班级。通常不建议出于微不足道的原因(例如性能)来防止继承,因为代码重用通常会超过通过标记类final可以实现的小的性能提升。

话虽如此,这里有几个例子,你可能想要明确地阻止继承:

  1. 您正在编写一个商业的闭源类,并且您不希望人们能够更改功能。这是防止类继承的一个很好的理由,因为如果人们已经覆盖了你的方法和/或扩展你的类,并且抱怨他们得到了意想不到的结果,你不希望以后必须支持它。

  2. 您正在设计一个不可变类。通过标记类final,您可以防止子类破坏类的不可变行为。例如,如果允许您继承String,则其他人可以创建允许String修改的自己的实现。现在,没有采用类型String的代码可以确定该对象是不可变的。

  3. 您想强制composition over inheritance。当你想要避免类之间的紧密耦合时(即你不希望彼此高度依赖的类组),这是可取的。

  4. 您希望鼓励编译器进行内联。将类和方法标记为final可能会导致性能提升,因为它将确保Java不必在运行时查找正确的类方法来调用对象。非final方法被标记为虚拟,以便在需要时可以正确扩展它们,最终方法可以在类中直接链接或编译。请注意,通过这样做可以获得的性能提升通常是微不足道的(特别是如果您的课程方法很大)。

答案 1 :(得分:3)

事实上,我试图遵循的做法,以及Josh Bloch在他的 Effective Java 一书中推荐的做法,正好与你被告知的做法相反:除非你已经考虑了继承,设计了你的类继承,并记录了你的类必须如何继承,你应该总是禁用继承。

我建议您阅读有效Java的这一章(您不会后悔购买它),并将其展示给告诉您有关此规则的人。

不允许继承的最明显原因是不变性。不可变对象易于使用(只有一个状态),可以缓存,在许多对象之间共享,并且本质上是线程安全的。如果该类是可继承的,那么任何人都可以通过添加可变属性来扩展该类并使其可变。

答案 2 :(得分:3)

这是我的0.02 ......

允许人们在课堂上继承可以解决无法预料的问题。 (例如,经常出现在RoR中的monkeypatching。它可能是丑陋的,但它是现实与迂腐)。话虽如此,我不是无偿继承的忠实粉丝。基类和子类之间的关系可能很脆弱。深层继承层次结构很难理解。

我认为不允许继承的一个案例是强制执行不变性。这对Java String类很重要。