我应该将方法设置为虚方法还是抽象方法?

3

我有一个抽象类,它可以自行进行内部验证。另外,还有一个方法允许子类进行附加的验证检查。目前,我已将该方法设为抽象.

protected abstract bool ValidateFurther();

然而,我发现相当多的子类只是为了返回true而被迫覆盖它。我在考虑将该方法设置为virtual

protected virtual bool ValidateFurther() => true;

在抽象类中假设验证程序将正常工作是不好的吗?我担心子类可能注意不到它,并最终在需要覆盖它时未能这样做。这里哪种方法更合适?


1
让派生类实现某些内容,可以将其留作抽象。 - pm100
2
我们没有更多的上下文信息,无法给出准确答案。 - Caius Jard
4个回答

1
你可以在设计中再添加一层。
public abstract class Base
{
    protected abstract bool ValidateFurther();
}

public abstract class BaseWithValidation : Base
{
    protected override bool ValidateFurther() => true;
}

如果您继承的类中有一个重要的子集只需要返回 true,那么您可以使用 BaseWithValidation 来避免在每个地方重复代码;否则,请使用 Base

可能更好的命名方式是 BaseWithNoFurtherValidation - Frank Fajardo
另外,IFurtherValidatable接口可能是一个解决方案。 - Franz Gleichmann
一个“没有验证的基类”拥有Validate方法是毫无意义的。 - Flater

0
  • 抽象方法意味着您只想定义要遵循的行为,并让子类执行实现。
  • 虚拟方法意味着您定义了一个具有初始实现的方法,但允许被覆盖。

因此,也许您可以更详细地解释您的上下文,然后我们可以讨论它!


0

将方法定义为virtual,并定义一个返回true的默认实现是可以的。

protected virtual bool ValidateFurther() => true;

抽象方法和虚方法的区别在于,抽象方法只定义了方法的签名,实现留给派生类来实现(类似于接口)。所有子类都需要实现抽象方法的逻辑。你可以查看文档以获取更多详细信息。
另一方面,virtual 要求你实现逻辑,如果需要,你可以 override 该方法以添加/扩展逻辑。由于你有默认逻辑,所以你的子/派生类不需要 override 它。你可以查看文档以获取更多详细信息。
基本上,将方法实现为 virtual 并默认返回 true 是可行的。
FYI:从 C# 8 开始,接口中可以有默认实现链接

0

简短的回答

如果这个类(以及所有派生类)的目的并不总是需要验证,那么你应该选择virtual,否则选择abstract

换句话说,验证是否是这个类的核心目的? (是=抽象,否=虚拟)

我认为在这里使用virtual是更好的方法,但原因并非您想象的那样。本回答的其余部分详细阐述了为什么您的推理不是决定因素,以及真正的决定因素是什么。


你的推理

我看到很多子类被迫重写它只是为了返回true。

我怀疑你正在屈服于程序员的反应:"我看到这个重复出现了,必须编写代码来避免这种重复!"

虽然这通常是一个好方法,但当你开始将其应用于那些恰好是相同而不是表达相同功能目的的事情时,它也可能被误用。

我经常使用以下示例来解决这个问题:

public class Book
{
    public string Title { get; set; }
    public DateTime CreatedOn { get; set; }
}

public class EmployeeJob
{
    public string Title { get; set; }
    public DateTime CreatedOn { get; set; }
}

CreatedOn属性抽象化确实有价值,因为这些实体都是审计数据实体。 CreatedOn属性是该审计实体的一部分,并且它在BookEmployeeJob中的存在源于这些类都是审计实体。

如果对审计实体进行更改(例如,它们不再跟踪创建日期),则该更改需要自动持久化到所有审计实体。当您使用共享逻辑时,这会自动发生。

但是,Title需要被抽象成共享逻辑吗?不需要。这里没有功能重叠。是的,这些属性具有相同的名称和类型,但它们根本没有共同的逻辑。它们只是恰好现在相等,但它们彼此之间没有联系。

如果对一个Title属性进行更改(例如,它现在变成了作业标题表的Guid FK),那么该更改不会自动反映在另一个属性上(例如,书名仍然只是一个字符串)。实现这些Title属性使用共享逻辑实际上会在以后引起问题而不是解决问题。

简而言之:有时程序员会寻求比他们需要的更多的模式。或者如果你允许我引用《侏罗纪公园》quote Jurassic Park

决定因素

我正在考虑将该方法设置为虚拟的。

无论您将其设置为抽象还是虚拟,都取决于一个特定的考虑因素(不是DRY,如上所述):您是否希望提供默认实现,还是更喜欢强制每个使用者(即派生类)自行评估此方法的实现?

这两种方法都没有客观上的优劣之分,而是取决于哪种最适合您当前的情况。

我看到有相当多的子类被迫重写它只是为了返回true。

我从中推断出,在这些类中,您基本上跳过了验证,因此在这种情况下,我会选择使用virtual方法,因为这个类(以及所有派生类)的目的并不总是需要验证(再次说明,这是基于您的解释进行的我的解释)。

换句话说,验证是否是这个类目的的核心?(是=抽象,否=虚拟)。由于您没有指定您的类或其目的,因此我无法做出最终决定。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接