我最近接受了两次电话采访,被问及接口类和抽象类之间的区别。我已经解释了我能想到的每一个方面,但似乎他们在等我提一些具体的事情,我不知道是什么。

根据我的经验,我认为以下是正确的。如果我遗漏了一个要点,请告诉我。

接口:

接口中声明的每个方法都必须在子类中实现。接口中只能存在事件、委托、财产(C#)和方法。一个类可以实现多个接口。

抽象类:

子类只能实现抽象方法。抽象类可以具有具有实现的普通方法。除了事件、委托、财产和方法之外,抽象类还可以有类变量。由于C#中不存在多重继承,一个类只能实现一个抽象类。

在这之后,面试官提出了一个问题:“如果你有一个只有抽象方法的抽象类呢?这和接口有什么不同?”我不知道答案,但我认为这是上面提到的继承,对吧?另一位面试官问我,“如果你在接口中有一个公共变量,那会和抽象类中有什么不同?”我坚持认为你不能在接口中使用公共变量。我不知道他想听什么,但他也不满意。

另请参阅:

何时使用接口而不是抽象类,反之亦然接口与抽象类如何决定使用抽象类和接口?接口和抽象类之间的区别是什么?


当前回答

虽然您的问题表明它是针对“通用OO”的,但它似乎真正关注的是.NET对这些术语的使用。

在.NET中(类似于Java):

接口可以没有状态或实现实现接口的类必须提供该接口的所有方法的实现抽象类可以包含状态(数据成员)和/或实现(方法)抽象类可以在不实现抽象方法的情况下继承(尽管这样的派生类本身是抽象的)接口可能是多继承的,抽象类可能不是(这可能是接口与abtract类分开存在的关键具体原因——它们允许实现多继承,从而消除了一般MI的许多问题)。

作为通用OO术语,差异不一定定义明确。例如,有些C++程序员可能持有类似的严格定义(接口是抽象类的严格子集,不能包含实现),而有些人可能会说,具有某些默认实现的抽象类仍然是接口,或者非抽象类仍然可以定义接口。

事实上,有一种叫做非虚拟接口(NVI)的C++习惯用法,其中公共方法是“thunk”到私有虚拟方法的非虚拟方法:

http://www.gotw.ca/publications/mill18.htmhttp://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-虚拟界面(_I)

其他回答

抽象类处理有效地打包类功能,而接口用于意图/契约/通信,并且应该与其他类/模块共享。

使用抽象类作为契约和(部分)契约实现者违反了SRP。使用抽象类作为契约(依赖关系)限制了创建多个抽象类以获得更好的重用性。

在下面的示例中,使用抽象类作为OrderManager的合同会产生问题,因为我们有两种不同的处理订单的方式-基于客户类型和类别(客户可以是直接或间接的,也可以是黄金或白银)。因此,接口用于契约,抽象类用于不同的工作流实施

public interface IOrderProcessor
{
    bool Process(string orderNumber);
}

public abstract class CustomerTypeOrderProcessor: IOrderProcessor
{
    public bool Process(string orderNumber) => IsValid(orderNumber) ? ProcessOrder(orderNumber) : false;

    protected abstract bool ProcessOrder(string orderNumber);

    protected abstract bool IsValid(string orderNumber);
}

public class DirectCustomerOrderProcessor : CustomerTypeOrderProcessor
{
    protected override bool IsValid(string orderNumber) => string.IsNullOrEmpty(orderNumber); 

    protected override bool ProcessOrder(string orderNumber) => true; 
}

public class InDirectCustomerOrderProcessor : CustomerTypeOrderProcessor
{
    protected override bool IsValid(string orderNumber) => orderNumber.StartsWith("EX");

    protected override bool ProcessOrder(string orderNumber) => true;
}

public abstract class CustomerCategoryOrderProcessor : IOrderProcessor
{
    public bool Process(string orderNumber) => ProcessOrder(GetDiscountPercentile(orderNumber), orderNumber);

    protected abstract int GetDiscountPercentile(string orderNumber);

    protected abstract bool ProcessOrder(int discount, string orderNumber);
}

public class GoldCustomer : CustomerCategoryOrderProcessor
{
    protected override int GetDiscountPercentile(string orderNumber) => 15;

    protected override bool ProcessOrder(int discount, string orderNumber) => true;

}

public class SilverCustomer : CustomerCategoryOrderProcessor
{
    protected override int GetDiscountPercentile(string orderNumber) => 10;

    protected override bool ProcessOrder(int discount, string orderNumber) => true;

}

public class OrderManager
{
    private readonly IOrderProcessor _orderProcessor;// Not CustomerTypeOrderProcessor or CustomerCategoryOrderProcessor 

    //Using abstract class here would create problem as we have two different abstract classes
    public OrderManager(IOrderProcessor orderProcessor) => _orderProcessor = orderProcessor;
}

我将解释接口和抽象类的深度细节。如果您了解接口和抽象类别的概述,那么第一个问题就会出现在您的脑海中,我们应该何时使用接口,何时使用抽象类别。因此,请检查以下接口和抽象类的说明。

我们什么时候应该使用界面?如果您不了解实现,我们只有需求规范,那么我们就使用Interface我们什么时候应该使用抽象类?如果您知道实现但不完全(部分实现),那么我们使用抽象类。界面默认情况下,每个方法的公共抽象意味着接口是100%纯抽象的。摘要可以有Concrete方法和Abstract方法,抽象类是一个声明为抽象的类,它可以包含也可以不包含抽象方法。界面我们不能将接口声明为私有的、受保护的问:为什么我们不将接口声明为私有和受保护的?因为默认情况下接口方法是公共抽象的,所以我们没有将接口声明为私有和受保护的。接口方法我们也不能将接口声明为private、protected、final、static、synchronized、native。。。。。我会给出原因:为什么我们不声明synchronized方法,因为我们无法创建接口的对象,而synchronization是在对象上工作的,这也是我们不声明synchronized的原因瞬态概念也不适用,因为瞬态工作与同步。摘要我们很乐意使用公共的、私人的最终静态。。。。表示抽象上不适用任何限制。界面默认情况下,变量在接口中声明为公共静态final,因此我们也不会将变量声明为私有的受保护变量。易失性修饰符也不适用于接口,因为接口变量默认为公共静态final和final变量。一旦它将值分配给变量,您就不能更改该值,一旦您将变量声明给接口,您就必须分配该变量。易失性变量是不断变化的,所以它是最后一个,这就是我们不在接口中使用易失性的原因。摘要抽象变量不需要声明公共静态final。

我希望这篇文章有用。

其他一些区别:

抽象类可以有静态方法、财产、字段等,而操作符和接口则不能。强制转换运算符允许向抽象类强制转换,但不允许向接口强制转换。

所以,即使抽象类从未实现(通过它的静态成员),也可以单独使用抽象类,并且不能以任何方式单独使用接口。

抽象类不是纯抽象的,因为它是具体(实现的方法)和未实现的方法的集合。但是接口是纯抽象的,因为只有未实现的方法,而没有具体的方法。

还有一个区别是

抽象类允许您创建子类可以实现或覆盖的功能。接口只允许您定义功能,而不允许实现它。

何时使用抽象类

如果用户希望为所有对象编写通用功能。抽象类是未来重新实现的最佳选择,它可以在不影响最终用户的情况下添加更多功能。

何时使用接口

如果用户希望编写不同的功能,则对象上的功能将不同。接口是最好的选择,如果接口发布后不需要修改需求。

从概念上讲,保持特定于语言的实现、规则、好处,并通过使用任何人或两者实现任何编程目标,可以或不可以有代码/数据/属性等等,单继承或多继承等等

1-抽象(或纯抽象)类旨在实现层次结构。如果您的业务对象在结构上看起来有些相似,仅表示父子(层次结构)类型的关系,那么将使用继承/抽象类。如果您的业务模型没有层次结构,那么就不应该使用继承(这里我不是在谈论编程逻辑,例如一些设计模式需要继承)。从概念上讲,抽象类是一种在OOP中实现业务模型层次结构的方法,它与接口无关,实际上将抽象类与接口进行比较是没有意义的,因为两者在概念上完全不同,在访谈中要求它只是为了检查概念,因为当涉及到实现时,它看起来都提供了一些相同的功能,而我们程序员通常更强调编码。[请记住,抽象与抽象类不同]。

2-接口是一个契约,一个由一组或多组功能表示的完整业务功能。这就是它被实现而不是继承的原因。业务对象(是否是层次结构的一部分)可以具有任意数量的完整业务功能。它与抽象类无关,通常意味着继承。例如,人可以跑步,大象可以跑步,鸟可以跑步等等,所有这些不同层次的对象都将实现RUN接口或EAT或SPEAK接口。不要进入实现,因为您可能会将其实现为为实现这些接口的每种类型提供抽象类。任何层次结构的对象都可以具有与其层次结构无关的功能(接口)。

我相信,接口的发明并不是为了实现多重继承或公开公共行为,类似地,纯抽象类并不是为了推翻接口,而是接口是一个对象可以实现的功能(通过接口的功能),抽象类代表一个层次结构的父级,以生成具有父级核心结构(属性+功能)的子级

当你被问到差异时,这实际上是概念上的差异,而不是特定语言实现中的差异,除非被明确问到。

我相信,两位面试官都希望这两者之间有一条直线的直接区别,当你失败时,他们试图通过将“一个作为另一个”来驱使你实现这一区别

如果你有一个只有抽象方法的抽象类呢?