我和一位同事讨论过,他坚持认为在Java和C#这样的语言中,从来没有任何理由使用Pure Abstract基类,因为它只是意味着你无法避免缺乏多重继承
我觉得他错了,因为我一直以为如果一个东西是名词那么它就是一个对象,如果它是一个动词那么它就是一个界面。
例如,如果我想定义类型Bird
,我想在不实现它的情况下强制执行方法fly
,那么我会将它设为纯抽象类。
如果我想定义类型Flies
,我会将其作为方法fly
的接口。
Bird
可能会实施Flies
。
我错了吗?
编辑:
我能支持我观点的唯一可靠论点是,在未来的某个时刻,设计可能需要改变,以便鸟类可以吃。如果所有的鸟都吃同样的话,那么就需要将它添加到Bird
,使其不是纯粹的抽象。
如果Bird
是一个接口,这个改变只会是一场噩梦,因为我不知道从其他基类继承的东西是否也实现了我的Bird
接口,所以我不能只是重构我的问题。
答案 0 :(得分:10)
我至少可以想到一个很好的理由:您可以在以后扩展抽象类,而不会破坏向后兼容性:假设一个类/接口
abstract class/interface Foo {
void foo();
}
如果我们使用接口,我们现在确定无法向Foo添加其他功能。这可能会导致类似interface Foo2 implements Foo
。
另一方面,如果你有一个抽象类,只要你提供一个基本实现,你就可以轻松地为它添加另一个方法。
请注意,Java8将允许接口基本上做同样的事情 - 这对于想要更新其库以使用lambdas而不必破坏与已编写的数百万行代码的兼容性的库编写者非常有用。
答案 1 :(得分:6)
除了你的第一次编辑,即未来的一些要求。一个可能的用例可以声明一个常量并在抽象类中初始化它。
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");
}
}
答案 2 :(得分:1)
我对纯抽象类进行了一些搜索(自从我上次使用C ++以来已经有一段时间了),我能找到的唯一用例就是用C ++定义接口(没有接口)。 / p>
所以我想说如果你可以使用一个纯粹的抽象类,你可以选择一个接口,就像你的朋友说的那样。
但是,我从来没有想过在C#中使用纯抽象类,所以这可能是一个假设的问题。
答案 3 :(得分:0)
我想说接口和类都定义了对象。正如你自己所说的,动词转到方法 - 它们是这些对象的属性。在你的fly示例中,我将声明一个接口FlyingCreature
并在其中定义一个方法fly(因此你有Comparable
和Serializable
之类的接口而不是Serialize
和{{1你有方法Compare
)。还有关于你的另一个例子 - 鸟:如果你没有任何鸟的逻辑,那么你将它声明为接口。
接口用于声明不同类型的对象将具有的公共属性,它们按分类方式对它们进行分组。后记,使用您知道它们具有相同界面的事实,您将能够以相同的方式处理它们。
我没有看到纯抽象类有任何好处,因为我已经说过抽象类和接口都声明了对象。
答案 4 :(得分:0)
假设你有一个带有多个插件类型的插件系统,每个插件都实现了不同的接口。
现在,我们还说你正在使用反射来在运行时找到这些插件类。
由于它们是接口,因此一个插件可以是多种类型的插件。
如果您使每个插件类型成为一个抽象类,那么您可以控制继承层次结构并确保每个插件都是一个不同的类型。
因此纯抽象类和接口之间存在差异。它不是你需要使用的,但它既不是++,递归,也不是对象。
答案 5 :(得分:0)
我不久前读到了与此相关的内容。它基本上说如果项目链接在一起,那么使用抽象类。如果它描述了某些东西的属性,那么使用一个接口。
因此,使用你的例子,一只鸟将是一个抽象类,因为你想要一只老鹰或一只鹦鹉来自同一个地方。
如果您只是想要“传单”之类的东西,那么您可以将其设为界面,因为鸟类和飞机以及其他东西可能会实现界面,但它只有这一个属性,它们是共同的。
另一件需要考虑的事情是,在某些时候你可能想要为你的鸟实际提出一些具体的方法。毕竟所有的鸟都以相同的方式飞行所以你可能希望班级在鸟儿飞行时打印“襟翼襟翼”。如果您正在使用接口,则需要在每个类上执行此操作(或者引入新的基类),而如果您首先使用了抽象类,则只需在一个位置添加行为。