纯抽象类和接口之间的区别

本文关键字:区别 之间 接口 抽象类 | 更新日期: 2023-09-27 18:26:20

我正在和一位同事讨论,他坚持认为在Java和C#等语言中,从来没有任何理由使用纯抽象基类,因为它只是意味着你无法绕过缺乏多重继承的问题。

我觉得他错了,因为我一直认为,如果一个事物是名词,那么它就是一个宾语,如果它是一个动词,那么它就是一个接口。

例如,如果我想定义类型 Bird ,我想在不实现它的情况下强制执行方法 fly,那么我会把它变成一个纯粹的抽象类。

如果我想定义一个类型Flies,我会让它成为方法fly的接口。

Bird可能会实现Flies.

我错了吗?

编辑:

能给出的唯一可靠的论据来支持我的观点是,在未来的某个时候,设计可能需要改变,以便鸟类可以吃东西。如果所有的鸟都吃一样的东西,那么这需要添加到Bird,使其非纯抽象。

如果Bird是一个接口,那么这种更改将只是一场噩梦,因为我无法知道从其他基类继承的东西是否也实现了我的Bird接口,所以我不能只是重构我的问题。

纯抽象类和接口之间的区别

我至少可以想到一个很好的理由:你可以在以后扩展抽象类,而不会破坏向后兼容性: 假设一个类/接口

abstract class/interface Foo {
    void foo();
}

如果我们使用一个界面,我们现在肯定知道没有办法向Foo添加额外的功能。这可能会导致类似 interface Foo2 implements Foo .

另一方面,如果你有一个抽象类,你可以很容易地向它添加另一个方法,只要你提供一个基本的实现。

请注意,Java8 将允许接口做基本相同的事情 - 这对于希望更新其库以使用 lambda 的库编写者非常有用,而不必破坏与已编写的数百万行代码的兼容性。

除了您的第一次编辑,即一些未来的要求。一个可能的用例可以声明一个常量并在抽象类中初始化它。

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractPure implements ISomeInterface {
    public static final List<String> days = new ArrayList<String>();
    static{
        days.add("Monday");
        days.add("Tuesday");
        days.add("Wednesday");      
        days.add("Thursday");   
        days.add("Friday"); 
        days.add("Saturday");   
        days.add("Sunday"); 
    }
}

我对纯抽象类进行了一些搜索(自从我上次使用 C++ 以来已经有一段时间了(,我能找到的唯一用例是在 C++ 中定义接口(没有接口(。

所以我想说,如果你可以使用一个纯粹的抽象类,你不妨使用一个接口,就像你的朋友说的那样。

但是,我从未遇到过在 C# 中需要纯抽象类的情况,因此这可能是一个假设问题。

我会说接口和类都定义了对象。正如你自己所说,动词转到方法 - 它们是这些对象的属性。在您的 fly 示例中,我将声明一个接口FlyingCreature并在其中定义一个方法 fly(因此您有像 ComparableSerializable 这样的接口,而不是 SerializeCompare .你有方法 compareTo (。还有关于你的另一个例子 - bird:如果你对鸟没有任何逻辑,那么你把它声明为接口。

这些接口用于声明不同类型的对象将具有的公共属性,它们按分类对它们进行分组。后记,利用您知道它们具有相同界面的事实,您将能够以相同的方式处理它们。

我认为纯抽象类没有任何好处,因为我已经说过抽象类和接口都声明对象。

假设你有一个插件系统,有多个插件类型,每个插件类型都实现一个不同的接口。

现在,假设您正在使用反射在运行时查找这些插件类。

由于它们是接口,一个插件可以是多种类型的插件。

如果使每个插件类型

都成为抽象类,则可以控制继承层次结构,并且可以确保每个插件都是不同的类型。

所以纯抽象类和接口之间是有区别的。 这不是你需要使用的,但++、递归甚至对象也不是。

不久前我读过一些与此相关的内容。它基本上是说,如果这些项目链接在一起,那么使用一个抽象类。如果它描述了某物的属性,则使用接口。

因此,使用您的示例,鸟将是一个抽象类,因为您希望鹰或鹦鹉来自同一个地方。

如果你只是想要像"flyer"这样的东西,那么你会把它作为一个接口,因为鸟类、飞机和其他东西可能会实现这个接口,但它只有一个共同的属性。

另一件需要考虑的事情是,在某些时候,你可能想为你的鸟放一些具体的方法。毕竟,所有的鸟都以相同的方式飞行,所以你可能希望班级在鸟飞的时候打印"襟翼襟翼"。如果你使用一个接口,你需要在每个类上这样做(或者引入一个新的基类(,而如果你首先使用了一个抽象类,你只需要在一个地方添加行为。