何时使用接口而不是抽象类,反之亦然?

这可能是一个通用的OOP问题。 我想根据用法在接口和抽象类之间进行通用比较。

什么时候想使用一个接口,什么时候会想要使用一个抽象类


我写了一篇文章:

抽象类和接口

总结:

当我们谈论抽象类时,我们正在定义对象类型的特征; 指定一个对象是什么

当我们谈论一个接口并定义我们承诺提供的功能时,我们正在讨论建立一个关于该对象可以做什么的合同


抽象类可以具有共享状态或功能。 接口只是提供状态或功能的承诺。 一个好的抽象类将减少必须重写的代码量,因为它的功能或状态可以共享。 界面没有定义的信息要共享


就我个人而言,我几乎从不需要编写抽象类。

大多数时候我看到抽象类被(错误)使用,这是因为抽象类的作者正在使用“模板方法”模式。

“模板方法”的问题是它几乎总是有些重入 - “派生”类不仅知道它正在实现的基类的“抽象”方法,而且还知道基类的公共方法即使大多数时候不需要打电话给他们。

(过度简化)示例:

abstract class QuickSorter
{
    public void Sort(object[] items)
    {
        // implementation code that somewhere along the way calls:
        bool less = compare(x,y);
        // ... more implementation code
    }
    abstract bool compare(object lhs, object rhs);
}

所以在这里,这个类的作者写了一个通用算法,并打算让人们通过提供他们自己的“钩子”来“专门化”它 - 在这种情况下,“比较”方法。

所以预期的用法是这样的:

class NameSorter : QuickSorter
{
    public bool compare(object lhs, object rhs)
    {
        // etc.
    }
}

问题在于你不适当地将两个概念联系在一起:

  • 比较两个项目的方法(哪个项目应该先进行)
  • 一个排序项目的方法(即快速排序和合并排序等)
  • 在上面的代码中,理论上,“比较”方法的作者可以重新回到超类“排序”方法中......尽管在实践中他们将永远不想或不需要这样做。

    您为这种不需要的耦合付出的代价是很难更改超类,而且在大多数OO语言中,不可能在运行时更改超类。

    另一种方法是使用“策略”设计模式:

    interface IComparator
    {
        bool compare(object lhs, object rhs);
    }
    
    class QuickSorter
    {
        private readonly IComparator comparator;
        public QuickSorter(IComparator comparator)
        {
            this.comparator = comparator;
        }
    
        public void Sort(object[] items)
        {
            // usual code but call comparator.Compare();
        }
    }
    
    class NameComparator : IComparator
    {
        bool compare(object lhs, object rhs)
        {
            // same code as before;
        }
    }
    

    所以现在注意:我们所有的都是接口,以及这些接口的具体实现。 在实践中,你并不需要其他任何东西来进行高级OO设计。

    为了“隐藏”我们通过使用“QuickSort”类和“NameComparator”实现“排序名称”的事实,我们仍然可以在某处编写一个工厂方法:

    ISorter CreateNameSorter()
    {
        return new QuickSorter(new NameComparator());
    }
    

    每当你有一个抽象类时,你都可以做到这一点......即使在基类和派生类之间存在一种自然的可重入关系时,通常也会使它们变得明确。

    最后一个想法:我们上面所做的全部工作是通过使用“QuickSort”函数和“NameComparison”函数“编写”一个“NameSorting”函数......在功能性编程语言中,这种编程风格变得更加自然,用较少的代码。

    链接地址: http://www.djcxy.com/p/38137.html

    上一篇: When to use an interface instead of an abstract class and vice versa?

    下一篇: Best practice using abstract / virtual