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

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

接口:

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

抽象类:

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

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

另请参阅:

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


当前回答

接口:-==合约。无论哪个类实现它都必须遵循接口的所有规范。

一个实时的例子是任何ISO标记的产品。ISO给出了一套规则/规范,说明产品应该如何构建以及它必须具备的最小功能集。

这只是产品必须具备的财产的子集。SO只有在产品满足其标准时才会签署产品。

现在看看这个代码

public interface IClock{       //defines a minimum set of specification which a clock should have

    public abstract Date getTime();
    public abstract int getDate();
}
public class Fasttrack: Clock {
    // Must have getTime() and getTime() as it implements IClock
    // It also can have other set of feature like 
    public void startBackgroundLight() {
        // watch with internal light in it.
    }
    .... //Fastrack can support other feature as well
    ....
    ....
}

在这里,Fastrack被称为手表,因为它具有手表必须具备的所有功能(最小功能集)。

原因和时间摘要:

来自MSDN:

抽象类的目的是提供多个派生类可以共享的基类的公共定义。

例如,类库可以定义一个抽象类,该抽象类用作其许多函数的参数,并要求使用该库的程序员通过创建派生类来提供自己的类实现。抽象只是指如果你不能定义它,就将它完全声明为抽象。实现类将完成这个实现。

例如:假设我声明一个类配方是抽象的,但我不知道该是哪个配方然后我将推广这个类来定义任何菜谱的通用定义。菜谱的植入将取决于菜品的实现。

抽象类既可以由抽象方法组成,也可以由非抽象方法组成。因此,您可以注意到接口中的差异。因此,实现类不一定必须具有每个方法。您只需要重写抽象方法。

简单来说,如果您想要紧密耦合,请使用接口o/w,以防失去耦合抽象类

其他回答

当然,理解OOP中接口和抽象类的行为(以及语言如何处理它们)很重要,但我认为理解每个术语的确切含义也很重要。你能想象if命令不能完全按照这个词的意思工作吗?此外,实际上,一些语言正在减少,甚至更多地减少界面和抽象之间的差异。。。如果碰巧有一天这两个术语几乎相同,那么至少你可以定义它们中的任何一个应该用于何处(以及为什么)。

如果你阅读一些字典和其他字体,你可能会发现同一个词有不同的含义,但有一些共同的定义。我认为我在这个网站上找到的这两个意思真的非常好,非常适合。

接口:

使分离的、有时不相容的元素能够有效协调的事物或环境。

摘要:

集中于自身的东西,集中于任何更广泛或更普遍的事物或若干事物的本质;本质

例子:

你买了一辆车,它需要燃料。

你的汽车模型是XYZ,属于ABC类型,所以它是一辆具体的汽车,一辆汽车的具体实例。汽车不是实物。事实上,它是一组抽象的标准(质量)来创建特定的对象。简而言之,Car是一个抽象的类,它是“集中于自身的任何更广泛或更一般的东西的本质”。

应使用符合汽车手册规格的唯一燃油来加注汽车油箱。实际上,没有什么可以限制您添加任何燃油,但发动机只能在指定的燃油下正常工作,因此最好遵循其要求。该要求表示,与其他同类ABC汽车一样,该公司接受一套标准燃油。

在面向对象的视图中,ABC类型的燃料不应该被声明为一个类,因为没有特定类型的汽车的具体燃料。尽管您的汽车可以接受抽象类别燃油或车辆燃油,但您必须记住,您现有的车辆燃油中只有一部分符合规范,即满足汽车手册要求的燃油。简而言之,他们应该实现ABCGenreFuel接口,该接口“……使独立的、有时不兼容的元素能够有效地协调”。

补遗

此外,我认为你应该记住class这个词的含义,它是(来自前面提到的同一个网站):

类别:

一群人或事物由于共同的属性、特征、品质或特点而被视为组成一个群体;友善的

这样,类(或抽象类)不应只表示公共属性(如接口),而是表示具有公共属性的某种组。接口不需要表示一种。它必须表示公共属性。通过这种方式,我认为类和抽象类可以用来表示不应该经常改变其方面的事物,比如人类是哺乳动物,因为它代表了某些种类。种类不应该经常改变自己。

我认为他们不喜欢你的回应,因为你给出的是技术上的差异,而不是设计上的差异。对我来说,这个问题就像一个巨魔问题。事实上,接口和抽象类有着完全不同的性质,所以你无法真正比较它们。我将向您介绍接口的作用和抽象类的作用。

接口:用于确保契约和类之间的低耦合,以获得更可维护、可扩展和可测试的应用程序。

抽象类:仅用于在具有相同响应性的类之间分解某些代码。请注意,这是为什么多重继承在OOP中是一件坏事的主要原因,因为类不应该处理许多响应(而是使用组合)。

因此,接口具有真正的体系结构角色,而抽象类几乎只是实现的一个细节(当然,如果正确使用的话)。

从编码角度

如果抽象类只有抽象方法,则接口可以替换抽象类。否则,将抽象类更改为接口意味着您将失去继承提供的代码重用性。

从设计角度

如果它是“Is a”关系,并且您需要一个子集或所有功能,请将其保留为抽象类。如果是“应该做”的关系,请将其保留为界面。

决定你需要什么:只是策略执行,或者代码重用和策略。

除了将抽象类与接口进行比较之外,将抽象类和具体类进行比较是有意义的。

使用抽象类就像使用具体类一样,除非您不希望/无法在没有扩展的情况下实例化它们。让你不想/不能实现抽象方法的方法。

如果你喜欢类比,就把chrome当作一个抽象类(你不能把它当作浏览器,所以它不能被实例化),把chrome和opera当作从chrome派生的具体类,把浏览器插件结构当作接口。

接口:我们不实现(或定义)方法,而是在派生类中实现。我们不在接口中声明成员变量。接口表示HAS-A关系。这意味着它们是对象的遮罩。抽象类:我们可以在抽象类中声明和定义方法。我们隐藏了它的构造函数。这意味着没有直接从它创建对象。抽象类可以保存成员变量。派生类继承到抽象类,这意味着派生类中的对象不被屏蔽,它继承到抽象类别。这种情况下的关系是is-A。

这是我的看法。