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

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

接口:

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

抽象类:

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

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

另请参阅:

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


当前回答

从我的另一个答案来看,主要是关于何时使用一个而不是另一个:

根据我的经验,界面是最好的有几个类时使用每个都需要对相同的方法,以便可由其他代码互换使用将针对这些类的公共接口。最好的当协议很重要,但底层逻辑可能不同于每个类别。如果你不是复制逻辑,考虑抽象类或标准类继承相反

其他回答

接口是执行特定行为的轻量级方式。这是一种想法。

还有一些其他的区别-

接口不能有任何具体的实现。抽象基类可以。这允许您在那里提供具体的实现。这可以允许抽象基类实际上提供更严格的契约,而接口实际上只描述如何使用类。(抽象基类可以具有定义行为的非虚拟成员,这给了基类作者更多的控制权。)

一个类上可以实现多个接口。类只能从单个抽象基类派生。这允许使用接口的多态层次结构,但不允许抽象基类。这也允许使用接口进行伪多重继承。

抽象基类可以在v2+中修改,而不破坏API。对接口的更改正在破坏更改。

[C#/.NET特定]接口与抽象基类不同,可以应用于值类型(结构)。结构不能从抽象基类继承。这允许将行为契约/使用指南应用于价值类型。

Jeffrey Richter通过C#从CLR复制。。。

我经常听到这样一个问题,“我应该设计一个基类型还是一个接口?”答案并不总是清晰明了。

以下是一些可能对您有所帮助的指南:

■■ IS-A与CAN-DO关系A类型只能继承一个实现。如果导出类型不能声明与基类型的IS-A关系,不要使用基类型;使用接口。接口意味着CAN-DO关系。如果CAN-DO功能似乎属于对于各种对象类型,使用接口。例如,类型可以转换自身的实例类型可以将其自身的实例序列化(ISerializable),注意,值类型必须从System.ValueType派生,因此不能可以从任意基类派生。在这种情况下,您必须使用CAN-DO关系并定义接口。

■■ 易用性作为开发人员,定义从基类型,而不是实现接口的所有方法。基本类型可以提供许多功能,因此派生类型可能只需要对其行为进行相对较小的修改。如果提供接口,则新类型必须实现所有成员。

■■ 一致的实施无论接口合同记录得多么好每个人都不可能100%正确地履行合同。事实上,COM这就是为什么某些COM对象只能与微软Word或Windows Internet Explorer。通过为基础类型提供默认实现,您首先使用一种有效且经过良好测试的类型;那么你可以修改需要修改的零件。

■■ 版本控制如果向基类型添加方法,则派生类型继承新方法,您开始使用一种有效的类型,用户的源代码甚至不必重新编译。向接口添加新成员将强制接口的继承者更改它的源代码并重新编译。

打个比方吧:当我在空军时,我参加了飞行员培训,成为了一名美国空军飞行员。当时我没有资格驾驶任何飞机,必须参加飞机类型的训练。一旦我获得资格,我就是一名飞行员(抽象类)和一名C-141飞行员(具体类)。在我的一项任务中,我被赋予了一项额外的职责:安全员。现在我仍然是一名飞行员和C-141飞行员,但我也履行了安全员的职责(可以说,我执行了ISafetyOfficer)。飞行员不需要是安全员,其他人也可以这样做。

所有美国空军飞行员都必须遵守某些空军规定,所有C-141(或F-16或T-38)飞行员都是“美国空军飞行员”。任何人都可以成为安全员。因此,总结如下:

Pilot:抽象类C-141试验:混凝土等级ISafety Officer:接口

补充说明:这是一个类比,以帮助解释概念,而不是编码建议。看到下面的各种评论,讨论很有趣。

通过实现接口,您实现了组合(“has-a”关系)而不是继承(“is-a”关系”)。当涉及到设计模式等需要使用接口来实现行为组合而不是继承的事情时,这是一个需要记住的重要原则。