基类 VS 抽象方法上的空虚方法 [英] Empty virtual method on base class VS abstract methods

查看:40
本文介绍了基类 VS 抽象方法上的空虚方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我找不到对某些情况不太具体的问题,所以我会尽量使这个问题非常通用.

I couldn't find a question that was not too specific to some case, so I'll try to make this very generic.

例如,我们需要一组文档的提取器基类.每个文档都有其特定的属性,但它们最终都是文档.所以我们想为所有这些提供通用的提取操作.

We need an extractor base class to a set of documents, for example. Each document has its specific properties, but they're ultimately documents. So we want to provide common extraction operations for all of them.

尽管它们都是文档,但正如我所说,它们还是有所不同.有些可能有一些属性,但有些可能没有.

Even though they're all documents, as I said, they're somewhat different. Some may have some properties, but some may not.

假设我们有 Document 基抽象类,以及从它继承的 FancyDocumentNotSoFancyDocument 类.FancyDocument 有一个 SectionANotSoFancyDocument 没有.

Let's imagine that we have the Document base abstract class, and the FancyDocument and NotSoFancyDocument classes that inherit from it. The FancyDocument has a SectionA, the NotSoFancyDocument doesn't.

也就是说,您认为实现这一目标的最佳方式是什么?这是两个选项:

That said, what would you defend as the best way of implementing this? Here's the two options:

  • 基类上的空虚方法

基类上的空虚方法将允许程序员只覆盖对不同类型文档有意义的方法.然后我们将在抽象基类上有一个默认行为,它将返回方法的 default,如下所示:

Empty virtual methods on the base class would allow the programmer to only override the methods that make sense for the different types of documents. We would then have a default behavior on the abstract base class, which would be returning the default for the methods, like this:

public abstract class Document
{
    public virtual SectionA GetDocumentSectionA()
    {
        return default(SectionA);
    }
}

public class FancyDocument : Document
{
    public override SectionA GetDocumentSectionA()
    {
        // Specific implementation            
    }
}

public class NotSoFancyDocument : Document
{
    // Does not implement method GetDocumentSectionA because it doesn't have a SectionA
}

  • 具体空方法或具体方法抛出 NotImplementedException
  • 由于NotSoFancyDocument 没有SectionA,但其他有,我们可以只返回默认值 对于其中的方法,或者我们可以抛出一个 NotImplementedException.这将取决于程序的编写方式和其他一些事情.我们可以想出这样的东西:

    Since the NotSoFancyDocument does not have a SectionA, but the others do, we could either just return the default for the method in it, or we could throw a NotImplementedException. That would depend on how the program was written and some other things. We could come up with something like this:

    //// Return the default value
    
    public abstract class Document
    {
        public abstract SectionA GetDocumentSectionA();
    }
    
    public class FancyDocument : Document
    {
        public override SectionA GetDocumentSectionA()
        {
            // Specific implementation
        }
    }
    
    public class NotSoFancyDocument : Document
    {
        public override SectionA GetDocumentSectionA()
        {
            return default(SectionA);
        }
    }
    

    //// Throw an exception
    
    public abstract class Document
    {
        public abstract SectionA GetDocumentSectionA();
    }
    
    public class FancyDocument : Document
    {
        public override SectionA GetDocumentSectionA()
        {
            // Specific implementation
        }
    }
    
    public class NotSoFancyDocument : Document
    {
        public override SectionA GetDocumentSectionA()
        {
            throw new NotImplementedException("NotSoFancyDocument does not have a section A");
        }
    }
    

    就我个人而言,我确实认为抽象方法方法更好,因为它意味着嘿,我需要你能够将 SectionA 变成文档.我不在乎如何."而虚拟方法的意思是嘿,我这里有这个 SectionA.如果它对你来说不够好,请随时改变我的获取方式.".

    Personally, I do think that the abstract method approach is better, since it means "Hey, I need you to be able to get a SectionA to be a document. I don't care how." while the virtual method means "Hey, I do have this SectionA here. If it's not good enough for you, feel free to change the way I get it.".

    我确实认为第一个是面向对象编程气味的标志.

    I do think the first one is a sign of object oriented programming smell.

    您对此有何看法?

    推荐答案

    在这种情况下,基类应该对 SectionA 一无所知.派生类应实现该类型所需的额外属性.

    In this case the base class should know nothing of SectionA. The derived class should implement the extra properties that that type needs.

    对于某些操作,无论文档类型如何,另一个类都需要提取信息,您希望基类上的该方法理想地具有基本实现的虚拟化,并允许派生类在需要时覆盖它(例如 ToPlainText 只输出文档的所有部分将在 Document 上,FancyDocument 可以覆盖实现也输出 SectionA).

    For certain operations where another class needs to pull information out regardless of the type of document you will want that method on the base class ideally virtual with a basic implementation and allow derived classes to override it if needed (eg ToPlainText which would just output all the sections of a document would be on Document, FancyDocument can override the implementation to also output SectionA).

    对于另一个类不关心文档类型但关心它是否具有某些属性的实例,使用接口.IDocument 将拥有所有公共部分,而 Document 将实现它.IDocumentWithSectionA 将继承 IDocument 并且 FancyDocument 将实现它.然后,这让您可以派生出另一个具有 SectionA 的 NeitherFancyNorNotFancyDocument,它也可以实现 IDocumentsWithSectionA.

    For instances where another class doesn't care about the type of document but does care if it has certain properties use interfaces. IDocument would have all the common sections and Document would implement it. IDocumentWithSectionA would inheerit IDocument and FancyDocument would implement that. This then lets you derive another NeitherFancyNorNotFancyDocument that has SectionA which can also implement IDocumentsWithSectionA.

    显然,您有比 IDocumentWithSectionA 更有用的名称,但这取决于用例.

    Obviously You'd have more useful names than IDocumentWithSectionA but that depends on the usecase.

    TL;DR 使用抽象类来表示所有文档应该共有的内容和一些通用功能,使用接口作为说明文档具有什么内容的合同.

    TL;DR use the abstract class for what should be common to all documents and some common functionality, use interfaces as the contract saying what a document has.

    这篇关于基类 VS 抽象方法上的空虚方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆