【问题标题】:Default implementations of Abstract methods抽象方法的默认实现
【发布时间】:2008-11-28 12:39:28
【问题描述】:
我正在处理一个大型代码库,其中包含许多类和这些类的许多抽象方法。我很感兴趣人们对我在以下情况下应该做什么的看法。
如果我有一个带有抽象方法的类 Parent-A。将只有2个孩子。如果 Child-B 实现了 AbstractMethodA 但 Child-B 没有实现,因为它不适用。
我应该
- 从 parent 中删除 abstract 关键字并使用 virtual 或 dynamic?
- 提供方法的空实现。
- 提供一个在调用时会引发错误的实现。
- 忽略警告。
编辑:感谢所有答案。它证实了我的怀疑,这不应该发生。经过进一步调查,结果发现这些方法根本没有使用,所以我完全删除了它们。
【问题讨论】:
标签:
delphi
oop
abstract-methods
【解决方案1】:
如果 AbstractMethodA 不适用于 Child-B,则 Child-B 不应继承自 Parent-A。
或者取反例,如果 Child-B 继承自 Parent-A,并且 AbstractMethodA 不适用于 child,那么它也不应该在 parent。
通过在 Parent-A 中放置一个方法,您是说该方法适用于 Parent-A 及其所有子级。这就是继承的意思,如果你用它来表示不同的意思,你最终会和你的编译器发生严重的争论。
[编辑-也就是说,如果该方法确实适用,则 Mladen Prajdic 的答案很好,但对于所涉及的一个或多个类不应该做任何事情。什么都不做的方法在 IMO 与不适用的方法不同,但也许我们所说的“不适用”并不是同一件事]
另一种技术是无论如何都在 Child-B 中实现该方法,但让它做一些极端的事情,比如总是返回失败,或者抛出异常,或者其他什么。它可以工作,但应该被视为有点笨拙而不是干净的设计,因为这意味着调用者需要知道他们所拥有的被视为 Parent-A 的东西是真的一个child-B,因此他们不应该调用AbstractMethodA。基本上你已经抛弃了多态性,这是面向对象继承的主要好处。就我个人而言,我更喜欢这样做而不是在基类中实现抛出异常,因为这样子类就不会因为“忘记”实现该方法而“意外地”表现得不好。它必须实现它,如果它实现它不起作用,那么它会明确地这样做。糟糕的情况应该是嘈杂的。
【解决方案2】:
如果后代中的实现不是强制性的,那么您应该选择 1+2(即祖先中的空虚方法)
【解决方案3】:
我认为,一般来说,如果您一开始就无法实现所有抽象方法,则不应该从抽象类继承,但我知道在某些情况下这样做仍然有意义,(参见 Stream 类及其实现)。
我认为您应该只创建这些抛出 NotImplementedException 的抽象方法的实现。
您也可以尝试使用 ObsoleteAttribute 以便调用该特定方法将是编译时错误(当然除了抛出 NotImplementedException 之外)。请注意,ObsoleteAttribute 并不完全适用于此,但我想如果您对 cmets 使用有意义的错误消息,没关系。
强制代码示例:
[Obsolete("This class does not implement this method", true)]
public override string MyReallyImportantMethod()
{
throw new NotImplementedException("This class does not implement this method.");
}
【解决方案5】:
你可以使用接口。然后 Child-A 和 Child-B 都可以实现不同的方法,并且仍然从 Parent-A 继承。接口的工作方式类似于抽象方法,因为它们强制类实现它们。
【解决方案6】:
如果 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_ 继承。