5

C# 中的“sealed”关键字,Java 中的 Final。

因为我几乎从不创建任何图表,而且我只使用已经完成的类(来自框架),所以多年后我仍然不知道为什么有人会“锁定”一个类,所以它永远不会被扩展/继承。

它是有益的?是否有任何危害使所有类都可以从继承中扩展而放弃“密封”的可能性?

很抱歉在 2012 年问这个问题,OOP 在哪里是微不足道的,但我希望得到一个很好的解释和/或一个很好的阅读来源!因为对我来说毫无用处,我不敢相信这只是一个简单的概念。

但是在我搜索的任何地方,答案都是一样的:“标记一个类,防止它被其他人继承。”。

4

2 回答 2

7
  1. 安全性 - 继承类可能有权访问基类的内部部分,从而破坏封装

  2. 保留合同- 继承类可能会破坏基类提供的合同。参见 Liskov 替换原则

  3. Immutability - 2.的特例 - 继承类可以将可变字段引入不可变类

  4. 性能- 虚拟机可以积极优化这些类,例如假设方法永远不会被覆盖,避免虚拟调用

  5. 简单- 实现类似equals()的方法要简单得多,而无需担心继承

于 2012-09-25T17:42:06.723 回答
2

原因是,如果您允许子类化,并且对子类可以覆盖的方法没有限制,则对保留行为的基类进行更新仍然可以破坏子类。换句话说,从不是专门设计为扩展的类继承是不安全的(通过将特定方法指定为可覆盖并使所有其他方法final。)这被称为脆弱基类问题 - 请参阅本文以获取示例,并且本文对这个问题进行了更深入的分析。

如果基类不是为继承而设计的,并且它是公共 API(可能是库)的一部分,那么您现在就遇到了严重的麻烦。您无法控制谁对您的代码进行子类化,并且您无法仅通过查看基类来知道更改对子类是否安全底线是您要么设计无限继承,要么完全禁止它。


请注意,可能有有限数量的子类。这可以通过私有构造函数和内部类来实现:

class Base {
    private Base() {}

    (public|private) static final class SubA extends Base { ... }
    (public|private) static final class SubB extends Base { ... }
    (public|private) static final class SubC extends Base { ... }
}

内部类可以访问私有构造函数,但顶级类没有,因此您只能从内部对其进行子类化。这允许您表达“Base 类型的值可以是 SubA OR SubB OR SubC”的概念。这里没有危险,因为 Base 通常是空的(您并没有真正从 Base 继承任何东西)并且所有子类都在您的控制之下。

您可能会认为这是代码异味,因为您知道子类的类型。但是您应该意识到,这种实现抽象的替代方式是对接口的补充。当子类数量有限时,添加新函数很容易(处理固定数量的子类),但很难添加新类型(每个现有方法都需要更新以处理新子类)。当您使用接口或允许无限子类化时,添加新类型很容易(实现固定数量的方法),但很难添加新方法(您需要更新每个类)。一个人的优点就是另一个人的缺点。有关该主题的更详细讨论,请参阅On Understanding Data Abstraction, Revisited编辑:我的错; 我链接的论文讨论了不同的二元性(ADT 与对象/接口)。我真正想到的是Expression Problem


There's less severe reasons to avoid inheritance as well. Suppose you start with class A, then implement some new feature in subclass B, and later on add another feature in subclass C. Then you realize you need both features, but you can't create a subclass BC that extends both B and C. It's possible to get bitten by this even if you design for inheritance and prevent the fragile base class problem. Other than the pattern I showed above, most uses of inheritance are better replaced with composition - for example, using the Strategy Pattern (or simply using high-order functions if your language supports it.)

于 2014-01-14T15:12:03.400 回答