我正在处理一个大型代码库,其中有很多类以及这些类上的很多抽象方法。我很感兴趣人们对我在以下情况下应该做什么的看法。

如果我有一个带有抽象方法的 Parent-A 类。只会有2个孩子。如果 Child-B 实现 AbstractMethodA 但 Child-B 没有实现,因为它不适用。

我是不是该

  1. 从父级中删除抽象关键字并使用虚拟或动态?
  2. 提供该方法的空实现。
  3. 提供一个在调用时引发错误的实现。
  4. 忽略警告。

编辑:感谢所有的答案。这证实了我的怀疑,这不应该发生。经过进一步调查,发现这些方法根本没有被使用,所以我已经完全删除了它们。

有帮助吗?

解决方案

如果 AbstractMethodA 不适用于 Child-B,则 Child-B 不应继承 Parent-A。

或者采取相反的方法,如果 Child-B 继承自 Parent-A,并且 AbstractMethodA 不适用于子级,那么它也不应该在父级中。

通过将方法放入 Parent-A 中,您可以说该方法适用于 Parent-A 及其所有子项。这就是继承 方法, ,如果你用它来表示不同的意思,你最终会与你的编译器发生严重的争执。

[编辑 - 也就是说,如果该方法确实适用,Mladen Prajdic 的答案就很好,但对于所涉及的一个或多个类不应该做任何事情。在我看来,什么都不做的方法与不适用的方法不是一回事,但也许我们所说的“不适用”并不是同一件事]

另一种技术是无论如何在 Child-B 中实现该方法,但让它做一些激烈的事情,比如总是返回失败,或者抛出异常,或者其他什么。它有效,但应该被视为有点麻烦,而不是一个干净的设计,因为这意味着调用者需要知道他们所拥有的被视为 Parent-A 的东西是 真的 子 B,因此他们不应该调用 AbstractMethodA。基本上您已经放弃了多态性,这是面向对象继承的主要好处。就我个人而言,我更喜欢这样做,而不是在基类中使用抛出异常的实现,因为这样子类就不会因为“忘记”实现该方法而“意外地”表现得很糟糕。它必须实现它,如果实现它不起作用,那么它会明确地执行它。糟糕的情况应该是吵闹的。

其他提示

如果后代中的实现不是强制性的,那么您应该选择 1+2(即祖先中的空虚拟方法)

我认为,一般来说,如果您无法首先实现所有抽象方法,则不应从抽象类继承,但我知道在某些情况下这样做仍然有意义,(请参阅Stream 类及其实现)。

我认为您应该只创建这些抛出 NotImplementedException 的抽象方法的实现。

您还可以尝试使用 ObsoleteAttribute,以便调用该特定方法将引发编译时错误(当然,除了抛出 NotImplementedException 之外)。请注意,ObsoleteAttribute 并不完全适合用于此目的,但我想如果您使用带有注释的有意义的错误消息,那就没问题了。

强制性代码示例:

[Obsolete("This class does not implement this method", true)]
public override string MyReallyImportantMethod()
{
    throw new NotImplementedException("This class does not implement this method.");
}

在基类中使其虚拟为空,并在子类中覆盖它。

您可以使用接口。那么Child-A和Child-B都可以实现不同的方法,并且仍然继承自Parent-A。接口的工作方式类似于抽象方法,因为它们强制类实现它们。

如果 A 的某些子类(B1、B2、...)与其他子类(C1、C2、...)用于其方法的不同子集,则可能会说 A 可以拆分为 B 和 C。

我不太了解 Delphi(一点也不:)),但我认为就像例如在Java和COM中,一个类可以“实现”多个接口。在 C++ 中,这只能通过多重继承抽象类来实现。

更具体:我将创建两个抽象类(带有抽象方法),并更改继承树。

如果这不可能,解决方法可能是“适配器”:一个中间类 A_nonB_,所有 B 方法都实现为空(并在调用它们时产生警告),以及 A_nonC_。然后更改继承树来解决您的问题:B1、B2、...继承自 A_nonC_ 和 C1, C2,...从 A_NonB_ 继承。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top