Jon*_*eet 62
好吧,正如许多其他人所说的......
是的,我认为建议默认密封课程是完全合理的.
这与Josh Bloch在他的优秀书籍Effective Java,第2版中的推荐一致:
设计继承,或禁止它.
设计继承很困难,并且可能使您的实现不那么灵活,特别是如果您有虚拟方法,其中一个调用另一个.也许他们是超载,也许他们不是.一个人调用另一个的事实必须记录在案,否则你不能安全地覆盖任何一种方法 - 你不知道它何时被调用,或者你是否可以安全地调用另一种方法而不会有堆栈溢出的风险.
现在,如果您以后想要更改哪个方法在更高版本中调用,则不能 - 您可能会破坏子类.因此,以"灵活性"的名义,您实际上使实现变得不那么灵活,并且必须更密切地记录您的实现细节.这对我来说听起来不是一个好主意.
接下来是不变性 - 我喜欢不可变类型.我发现它们比可变类型更容易推理.这是一个原因,为什么约达时间 API比使用更好Date,并Calendar在Java中.但是,一个未密封的类永远不会被认为是不可变的.如果我接受一个类型的参数Foo,我可能依赖于声明Foo的属性不会随着时间的推移而改变,但我不能依赖于对象本身没有被修改 - 在子类中可能有一个可变属性.如果某个虚拟方法的覆盖也使用了该属性,则Heaven帮助我.挥手告别不变性的许多好处.(具有讽刺意味的是,Joda Time拥有非常大的继承层次结构 - 通常会说"子类应该是不可变的.大型继承层次结构Chronology使得在移植到C#时很难理解."
最后,还有过度使用继承的方面.就个人而言,在可行的情 我喜欢接口的多态性,有时我会使用继承的实现 - 但它很少适合我的经验.密封课程可以避免不适当地从合成更合适的地方获得.
编辑:我还想向读者指出Eric Lippert在2004年发表的关于为什么这么多框架类被密封的博客文章.有很多地方我希望.NET提供一个我们可以用来测试的接口,但这是一个稍微不同的请求......
Jer*_*xon 20
我认为,架构设计决策是为了与其他开发人员(包括未来的维护开发人员)沟通的重要事项.
密封类传达不应覆盖实现.它表示不应该冒充该类.密封是有充分理由的.
如果你采取不同寻常的方法来封装所有东西(这是不寻常的),那么你的设计决策现在可以传达非常重要的东西 - 就像那个类不打算由原始/创作开发者继承.
但随后你将如何传达给其他开发类应该不是因为什么被继承?你真的不能.你被卡住了
而且,密封课程并不会提高可读性.我只是没有看到.如果继承是OOP开发中的问题,那么我们就会遇到更大的问题.
我想我是一个经验丰富的程序员,如果我没有学到任何东西,那就是我在预测未来方面非常糟糕.
打字密封并不难,我只是不想激怒开发人员(可能是我!)谁发现问题可以通过一点继承轻松解决.
我也不知道密封类如何使它更具可读性.你是否试图强迫人们更喜欢作曲继承?
\xc2\xa9 杰弗里·里希特
\n\n\n\n密封类比未密封类更好的原因有以下三个:
\n\n\n
\n- 版本控制:当一个类最初是密封的时,它可以在将来更改为未密封的,而不会破坏兼容性。但是,一旦\n类被解封,您将来就无法将其更改为\n密封,因为\n这会破坏所有派生类。\n此外,如果未密封的类\n定义了任何未密封的虚拟方法,\n必须在新版本中维护虚拟方法调用的顺序,否则将来可能会破坏派生类型。
\n- 性能:如上一节所述,调用虚拟方法的执行效果不如调用非虚拟方法,因为 CLR 必须在运行时查找对象的类型以便确定哪种类型定义了要调用的方法。但是,如果 JIT\n 编译器发现使用密封类型对虚拟\n 方法的调用,则 JIT\n 编译器可以通过非虚拟\n 调用该方法\n 来生成更高效的代码。它可以这样做是因为\n 它知道如果该类是密封的,则可能\xe2\x80\x99t 可能是派生类。
\n- 安全性:和可预测性 类必须保护自己的状态,并且不允许自己被损坏。当类解封时,派生类可以访问和操作基类xe2x80x99s说明任何数据字段或内部操作字段的方法是否可访问且不是私有的。此外,虚拟方法可以由派生类重写,并且派生类可以决定是否\n调用基类\xe2\x80\x99s 实现。\n 通过将方法、属性或事件设置为虚拟,\n 基类将放弃\n 对其行为及其状态的部分控制。除非经过深思熟虑,否则这可能会导致对象行为不可预测,并造成潜在的安全漏洞。
\n
坦率地说,我认为在 c# 中默认情况下没有密封的类有点奇怪,并且与其他默认值在语言中的工作方式格格不入。
默认情况下,类是internal. 默认字段是private. 默认情况下,成员是private.
默认情况下,似乎有一种趋势指向最不合理的访问。一个unsealed关键字应该在 c# 中退出而不是sealed.
就我个人而言,我宁愿默认情况下密封类。在大多数情况下,当有人编写一个类时,他在设计它时并没有考虑到子类化以及随之而来的所有复杂性。为未来的子类化设计应该是一种有意识的行为,因此我希望您必须明确说明这一点。
继承一个类应该没有任何错误.
你应该只在有一个很好的理由不应该继承的时候封一课.
此外,如果你全部密封,它只会降低可维护性.每当有人想从你的某个班级继承,他就会看到它是密封的,然后他要么取消印章(弄乱他不应该乱用的代码)或者更糟糕的是:创建一个糟糕的实施你的为自己上课.
那么你将有2个相同的实现,一个可能比另一个更糟糕,并且需要维护2个代码.
更好的是保持开封.没有密封它没有伤害.