Inheritance 断开多态性与未使用继承成员的子类

Inheritance 断开多态性与未使用继承成员的子类,inheritance,polymorphism,Inheritance,Polymorphism,如果我使用继承,并且后来意识到单个子类需要一个不可用的方法或字段,那么我应该在基类中声明它,而不是在其他子类中实现它,还是应该在该单个子类中声明它 如果我选择在子类中声明方法,那么我就不能再以多态方式处理所有内容。另一方面,如果我选择把它放在基类中,那么我最终会得到很多子类,它们没有实现属性或方法。我在.net框架中看到过选择“未实现”方法的示例。最好的方法是什么?它是只需要一个子类的专用方法吗?然后在子类中实现。否则,在抛出NotImplementedException的基类中实现为虚拟。然后

如果我使用继承,并且后来意识到单个子类需要一个不可用的方法或字段,那么我应该在基类中声明它,而不是在其他子类中实现它,还是应该在该单个子类中声明它


如果我选择在子类中声明方法,那么我就不能再以多态方式处理所有内容。另一方面,如果我选择把它放在基类中,那么我最终会得到很多子类,它们没有实现属性或方法。我在.net框架中看到过选择“未实现”方法的示例。最好的方法是什么?

它是只需要一个子类的专用方法吗?然后在子类中实现。否则,在抛出NotImplementedException的基类中实现为虚拟。然后在任何需要它的类中添加为重写。

如果只有一个子类具有方法X,那么根据定义,当然不能以多态方式调用X。X存在于超类中(因此无处不在),但在大多数情况下都是不可操作的,这合理吗?有时是这样,有时你只需要重新思考你的整个类层次结构,例如,为什么你想以多态方式调用X,即使它可能不存在(或者充其量是不存在的)?如果不了解更多关于特定用例的信息,就不可能做出响应

如果它只在子类中使用,不需要多态调用,那么只在子类中实现它。然而,如果您需要以多态方式使用它,那么请考虑该函数对于该超类的其他子类意味着什么

如果该函数没有什么好的意义,那么您可能需要重新考虑您的类层次结构。但是,对于函数没有有效意义的子类,您可以不执行任何操作或抛出NotImplementedException。我对这两种方法都不是很感兴趣,但有时没有办法使用它们。

除非每个可能的派生类都有适当的实现,否则方法不属于基类

如果您必须在某些派生中抛出NotSupportedException,那么您已经打破了这个规则。这个主体基本上声明,只要需要基类,任何派生类都应该是合适的。

类的公共接口应尽可能具有内聚性。如果遇到这样的选择,我几乎总是将其放入派生类中,除非我真的认为该操作“属于”基类

更新

我想收回我先前的发言。正如韦恩·哈特曼所指出的,如果这是真的,那么
System.IO.Stream
也会破坏LSP。规则声明您不能从子类型中的方法引发新异常。这似乎不适用于抽象方法,因为它们没有任何实现

我认为重要的一点是保持你的抽象纯粹。如果将方法添加到基类中在抽象方面是有意义的,那么一定要这样做。但是,如果您只想有一个公共位置来添加代码,那么我将避免将其添加到基础中


我也同意,有时部分实现一致性是合适的。

我一直倾向于对尚未完成的代码使用
NotImplemented
样式的异常。我个人不会为了能把更多的方法放入基类而使用它。

对于这一个,你需要回答一些关于API意图的问题

  • 如何使用您的API:如果您的API使用者几乎总是引用您的基类,那么将其放入基类可能是有意义的
  • 如果您尝试实现的方法适用于几乎所有可以选择实现该功能的派生类,则将其放入基类中

  • 考虑一下
    System.IO.Stream
    ,这是一个抽象类,具有用于搜索操作的抽象方法,不必从类似
    System.IO.SeekableStrem
    的东西派生就可以获得搜索功能,API的用户应该只参考

    我的想法是多态性远远超过了一系列未实现的方法。我只是想了解一下社区的想法在你构建一个应用程序之后,在某个地方你会得到新的需求(变化是不断的),现在你不得不担心改变你的整个架构。像这样的情况导致了项目崩溃。@CodingJoy,我从未见过项目因为使用“太少的继承”而崩溃,尽管我见过相反的情况:继承是非常紧密的耦合(这就是为什么Gof4说“更喜欢组合而不是继承”)。一种具有多态性的语言(仅通过签名或接口),但没有实现继承,同时可能需要通过组合进行更多的样板显式委托(我想这可能会被特定于语言的机制所避免),这将是一个有趣的游乐场…@CodingJoy-这通常是>>OO的卖点之一是多态性。如果我有一个foreach循环,在一些叫做账户的类上,它应该打印出一些报告,而不是打印出所有的账户,无论它们是储蓄账户、支票账户、货币市场账户、股票市场账户等等……对。。。但是,您需要确保对所有帐户调用的方法对每个帐户类型都有意义。在您的示例中,并非每种类型的帐户都有到期日等。。。因此,您可能不希望在到期日使用多态函数。如果您不介意的话,我在您的问题中添加了一些附加标记。如果是这样,则本机.NET流子类违反了这一原则。许多流不支持seek()方法,并最终引发NotSupportedException。虽然我同意利斯科夫替换原则是一个重要的生活理念,但有必要违反m