设计建议 - 何时有效使用"虚拟"和"密封"

Sap*_*pph 31 c# inheritance

我正在写一个C#网络库(主要是作为一个学习练习,如果有人真的最终使用它,那对我来说并不重要,因为我确信解决方案已经存在).

到目前为止,我对我的结构非常满意......我有几层客户端/服务器可用,可以通过套接字以原始字节进行通信,或者通过序列化消息对象稍微复杂一些.

我遇到的问题(问题?)是的时候正是我要声明的方法,属性或事件sealed,virtual或没有限定符.

我知道所有这些都做了什么 - sealed阻止了类的继承,或者进一步覆盖了一个方法.virtual将通过方法覆盖允许多态行为.

但是,由于我正在设计一个类库,所以我不确定何时使用它们.这是一个可扩展性的问题,我认为......我提供了一些接口,一个或两个抽象类,以及我的库的消费者使用或扩展的一些具体实现,但是我很难确定何时它是一个"好主意"明确禁止派生类或允许覆盖功能.

在设计我的类以供其他人使用时,请记住哪些一般指示或建议?

这个问题这一个是有些帮助的,因为是这一个,但因为我在写一个分配库我试图覆盖所有的我的基地.

Cra*_*ntz 25

开发类库Microsoft设计指南开始,特别是可扩展性部分,您可以在其中找到有关虚拟成员密封的文章.

引用,这里:

  • 除非您有充分的理由这样做并且您了解与设计,测试和维护虚拟成员相关的所有成本,否则不要将成员设置为虚拟成员.
  • 对虚拟成员更喜欢受保护的可访问性而不是公共可访问性.公共成员应通过调用受保护的虚拟成员来提供可扩展性(如果需要).

  • 如果没有充分的理由,不要上课.

  • 不要在密封类型上声明受保护或虚拟成员.
  • 考虑密封您覆盖的成员.

不过,请阅读完整的文章.

  • 那篇MSDN文章说不要在性能密集型领域使用代理和事件,但这仍然是多么准确(考虑到文章来自2005年)?从我的,无可否认的有限测试,调用委托与调用接口方法一样快,这是静态方法的两倍. (2认同)
  • 对于"除非你必须密封",我确信Jon Skeet将会深入探讨,否则会有一些哲学上的反对意见:) (2认同)

Eri*_*ert 20

首先,我同意其他答案,这些答案表明积极密封任何不是专门为扩展而设计的东西.我不同意你需要一个封印东西的理由; 相反,你需要一个理由留下未密封的东西.

你的问题非常笼统,所以这里有一个通用的答案:你的库可能是一组功能,可以作为解决用户问题的工具.您的库中的每个功能都可能是因为您进行了一些研究,发现存在需要解决的用户问题,并为他们解决了这个问题.

这些功能中的每一个都具有与之相关的特定成本.其中一些成本是过去的 - 您花费在设计,实现,测试,调试和发送代码上的时间.其中一些成本尚未到来:维护,阅读错误报告等.还有更微妙的成本,比如保持与现有功能之一的向后兼容性将提高明天实施新功能的成本.

可扩展性也是一个特性.这是一个功能,如果你弄错了,成本几乎完全在未来.像任何其他功能一样对待它:弄清楚它是否是您的用户真正需要的功能,以及它的好处是否支付其成本.如果您无法清楚地评估可扩展性的好处或成本,那么不小心实施它的风险很大.


Eri*_*sch 7

在我看来,你无法真正预见到你的用户最终将使用它.因此,除非存在一些您不希望用户捣乱的内部行为(即他们需要知道必须先在此之前设置,等等),否则通常不要密封任何东西.

对于虚拟,您倾向于使最终用户可能想要覆盖的任何虚拟内容.事件大大减少了对虚拟功能的需求,但仍有时候你想让它们成为虚拟功能.通常,您需要考虑最终用户可能需要定制任何给定成员函数的方式.


tee*_*yay 6

有很多次我说过"该死的!为什么这堂课被密封了??",但我从来没有说过"天哪 - 我希望他们能够密封那堂课!"

有一天,一个比你更好的程序员想要扩展你的课程,并且知道他们在做什么,这是一个很好的机会.我认为有很好的理由密封.