当前位置:  开发笔记 > 后端 > 正文

为什么要上课?

如何解决《为什么要上课?》经验,为你挑选了3个好方法。

我想知道.Net框架中大量密封类背后的动机是什么.密封课程有什么好处?我无法理解如何不允许继承有用,而且很可能不是唯一一个与这些类斗争的人.

那么,为什么框架以这种方式设计并且不会是开启一切的不间断的变化?必须有另一个原因,但只是邪恶?



1> Jon Skeet..:

类应该设计为继承或禁止它.设计继承需要付出代价:

它可以确定您的实现(您必须声明哪些方法将调用哪些其他方法,以防用户覆​​盖一个而不是另一个)

它揭示了您的实现,而不仅仅是效果

这意味着你必须在设计时考虑更多的可能性

像Equals这样的东西很难在继承树中设计

它需要更多文档

子类的不可变类型可能变得可变(ick)

有效Java的第17项详细介绍了这一点 - 无论它是在Java的上下文中编写的,这个建议也适用于.NET.

我个人希望在.NET中默认密封类.


嗯..如果你扩展课程,如果你打破它不是你的问题吗?
如果实现更改您无法在基类中进行控制,会怎样?这是谁的错?遗传基本上引入了脆弱性.支持组合优于继承促进了稳健性,IMO.
@Joan:作曲是一种"有一种"关系而不是"是一种".因此,如果您想编写一个类似于列表的类,但在其他方面却不行,您可能希望创建一个具有List 成员变量的类,而不是从List 派生.然后你*使用*列表来实现各种方法.
是的,界面很好 - 是的,无论如何,你可以赞成合成.但是如果我在没有仔细考虑它的情况下暴露一个未密封的基类,我应该期望更改可能会破坏派生类.这对我来说感觉很糟糕.IMO,更好地密封班级,避免破损.
@ThunderGr:但这就是我的观点:当您不需要担心子类提供的其他实现时,您可以更自由地使用自己的实现.例如,假设通过调用另一个方法实现一个方法,并且两个方法都是虚方法.这需要记录 - 即使它*感觉*就像一个实现细节.基本上,继承设计增加了手铐 - 这在某些情况下是合适的,但在其他情况下则不适用.我宁愿有一个密封的类实现一个接口,而不是一个带有一堆虚拟方法的未密封的类.
@ThunderGr很抱歉,但子类CAN会中断,即使对于保留超类行为的更改也是如此.证据需要比评论部分提供的空间更多的空间,但至少有[两个](http://www.cas.mcmaster.ca/~emil/Publications_files/MikhajlovSekerinski98FragileBaseClassProblem.pdf)[论文](http: //www.cs.cmu.edu/~aldrich/papers/selective-open-recursion.pdf)详细介绍了该主题.避免这个问题需要经过深思熟虑的设计决策,以禁止覆盖某些方法(参见第二篇论文).
真正.好的,如果您提供一些方法(可能是单独的接口)来编写您自己的实现以实现可测试性,这是有意义的.我花了一个多小时在这些类周围编写装饰器:)
@ThunderGr:你在谈论哪家公司?不,基类必须做更多的事情.如果任何一个虚方法调用另一个虚方法,则需要记录而不是更改 - 否则子类可能会被这种更改破坏.当一个类在设计时考虑了继承,它限制了以后更改实现的自由.当然,继承可能很有用 - 有时候.在其他时候,它可以增加复杂性而没有任何好处,其中组合会简化事情.这完全是一个背景问题.
我自己,我很少使用继承.通常,我更喜欢作曲.但是,继承是OOP的一个非常重要的特性.基类的*implementation*应该与派生类无关.基类的接口不应以使受保护或公共成员无效的方式更改.如果一个类不适合继承,那么它就是一个设计糟糕的类.任何不会破坏现有代码的类的更改都不应该破坏派生类.
@ThunderGr问题是大多数人甚至都不知道这是一个问题; 没有特别的预防措施你可以打破子类,这一点都不明显.OOP的大多数介绍性文本都提到了继承,就像这是一个伟大而聪明的东西 - 就像你作为一个程序员一样,你被期望大量使用它.除此之外,我并不完全清楚哪种情况实际上需要继承; 几乎所有的用途都是黑客,无法拥有一流的功能或总和类型.
@Stijn:不,如果子类添加了自己的状态,那么它是可能的.仅仅因为它没有明显的可变性,因为"Foo"并不意味着它仍然是不可改变的.(其他人可能会最终投射到子类.)

2> CVertex..:

有时课程太宝贵,而且不能被遗传.

运行时/反射可以在查找类型时对密封类进行继承假设.一个很好的例子是 - 建议密封查找运行时速度的属性.如果密封MyAttribute,type.GetCustomAttributes(typeof(MyAttribute))的执行速度会明显加快.

本主题的MSDN文章是通过密封类限制可扩展性.


@generalt:我相信设计继承或禁止它.设计继承需要相当多的工作,并且通常会限制将来的实现.继承还会给调用者带来不确定性,以确定他们将要调用什么.它也不能与不变性(我是它的粉丝)混在一起.我只发现类继承在相对较少的地方有用(而我喜欢接口).
这看起来像对我的坏建议:(
@CVertex:对不起,我并没有试图批评你 - 只是文章.
很高兴看到他们现在明确地说"谨慎使用"......希望他们能够实践他们所宣扬的东西.

3> Ohad Schneid..:

自从9年前提出这个问题以来,微软官方的密封指南似乎已经发生变化,并且他们从选择加入的理念(默认情况下的密封)转变为选择退出(默认情况下不密封):

X请勿在没有充分理由的情况下密封课程.

因为你无法想到可扩展性场景而封闭一个类并不是一个好理由.框架用户喜欢从各种非显而易见的原因继承类,比如添加便利成员.有关用户希望从类型继承的非显而易见原因的示例,请参阅未密封的类.

密封课程的充分理由包括:

该类是一个静态类.请参阅静态类设计.

该类在继承的受保护成员中存储安全敏感的机密.

该类继承了许多虚拟成员,并且单独密封它们的成本将超过使该类未密封的好处.

该类是一个需要非常快速运行时查找的属性.密封属性的性能水平略高于未密封的属性.请参阅属性.

X请勿在密封类型上声明受保护或虚拟成员.

根据定义,密封类型不能继承.这意味着无法调用密封类型上的受保护成员,并且无法覆盖密封类型上的虚方法.

✓考虑您覆盖的密封成员.引入虚拟成员可能导致的问题(在虚拟成员中讨论)也适用于覆盖,尽管程度稍低.从继承层次结构中的那一点开始,密封覆盖可以防止这些问题.

实际上,如果您搜索ASP.Net Core代码库,您将只发现大约30个sealed class,其中大多数是属性和测试类.

我认为不变性保护是支持密封的一个很好的论据.

推荐阅读
mobiledu2402851173
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有