我应该默认推荐密封等级吗?

2022-08-31 13:28:48

在我工作的一个大项目中,我正在考虑建议其他程序员总是密封他们的类,如果他们没有考虑他们的类应该如何被子类化。通常,经验不足的程序员从不考虑这一点。

我觉得奇怪的是,在Java和C#中,类是默认的非密封/非最终的。我认为将类密封大大提高了代码的可读性。

请注意,这是内部代码,如果发生我们需要子类化的极少数情况,我们可以随时更改它。

你有什么经验?我对这个想法遇到了相当多的阻力。懒惰的人不会被打扰打字?sealed


答案 1

好吧,正如许多其他人一样...

是的,我认为建议默认情况下密封类是完全合理的。

这与 Josh Bloch 在他的优秀著作《Effective Java,第 2 版》中的建议相吻合:

为继承而设计,或禁止继承。

针对继承进行设计非常困难,并且可能会使实现不那么灵活,尤其是在具有虚拟方法(其中一个方法调用另一个方法)时。也许它们是过载的,也许它们不是。必须记录一个调用另一个方法的事实,否则您无法安全地覆盖任何一个方法 - 您不知道何时调用它,或者是否可以安全地调用另一个方法而不会冒堆栈溢出的风险。

现在,如果您以后想要更改哪些方法调用了哪些方法,则在以后的版本中无法更改 - 您可能会破坏子类。因此,在“灵活性”的名义下,您实际上使实现变得不那么灵活,并且必须更密切地记录您的实现细节。对我来说,这听起来不是一个好主意。

接下来是不可变性 - 我喜欢不可变类型。我发现它们比可变类型更容易推理。这就是为什么Joda Time API比使用Java更好的原因之一。但是,一个未密封的类永远不可能被认为是不可变的。如果我接受一个类型的参数,我也许能够依靠Foo中声明的属性不会随着时间的推移而改变,但我不能依赖对象本身没有被修改 - 子类中可能有一个可变属性。如果该属性也被某些虚拟方法的覆盖使用,天堂会帮助我。挥手告别不可变性的许多好处。(具有讽刺意味的是,Joda Time具有非常大的继承层次结构 - 通常说“子类应该是不可变的。的较大继承层次结构使得在移植到 C# 时难以理解。DateCalendarFooChronology

最后,还有过度使用继承的方面。就个人而言,在可行的情况下,我更喜欢组合而不是继承。我喜欢接口的多态性,偶尔我使用实现的继承 - 但在我的经验中,它很少适合。将类密封可以避免从更适合组合的位置不恰当地派生它们。

编辑:我还想向读者指出Eric Lippert在2004年的博客文章,为什么这么多框架类都是密封的。在很多地方,我希望.NET提供一个我们可以用于可测试性的接口,但这是一个稍微不同的请求......


答案 2

我认为架构设计决策是为了传达给其他开发人员(包括未来的维护开发人员)一些重要的东西。

密封类传达不应重写实现。它传达了不应模拟该类的信息。密封是有充分理由的。

如果你采用不寻常的方法来密封所有内容(这是不寻常的),那么你的设计决策现在传达了一些真正不重要的东西 - 比如该类不打算由原始/创作开发人员继承。

但是,您将如何向其他开发人员传达该类不应该因为某些原因而被继承呢?你真的不能。你被困住了。

此外,密封类不会提高可读性。我只是没有看到这一点。如果继承是OOP开发中的一个问题,那么我们就有一个更大的问题。