我应该何时使用接口,何时使用基类?

如果我不想实际定义方法的基本实现,它应该始终是一个接口吗?

如果我有狗和猫的课。为什么我要实现IPet而不是PetBase?我可以理解为ISheds或IBarks(IMakesNoise?)提供接口,因为它们可以逐个宠物放置,但我不知道该为普通宠物使用哪个接口。


当前回答

Josh Bloch在《有效的Java 2d》中说道:

首选接口而非抽象类

一些要点:

可以很容易地对现有类进行修改,以实现新的界面你所要做的就是添加所需的方法(如果还没有)存在并将implements子句添加到类声明。接口是定义混合的理想选择。粗略地说mixin是类可以使用的类型除了“主要”键入“”以声明它提供一些可选行为。例如Comparable是一个mixin接口允许类声明其实例的排序依据其他相互可比较的对象。接口允许构造非分层类型框架。类型层次结构为很适合组织一些事情,但是其他的事情并不是很简单刚性层次。接口通过每类包装的习惯用法。如果您使用抽象类来定义类型留下想要添加的程序员功能,别无选择使用继承。此外,你可以结合这些优点接口和抽象类提供抽象骨架实现类导出的非平凡接口。

另一方面,接口很难发展。如果您向接口添加一个方法,它将破坏它的所有实现。

PS:买这本书。它要详细得多。

其他回答

让我们以Dog和Cat类为例,使用C#进行演示:

狗和猫都是动物,特别是四足哺乳动物(动物太普通了)。让我们假设您有一个抽象类Mammal,用于这两个类:

public abstract class Mammal

此基类可能具有默认方法,例如:

喂养朋友

所有这些都是在两个物种之间或多或少具有相同实现的行为。要定义此项,您需要:

public class Dog : Mammal
public class Cat : Mammal

现在让我们假设还有其他哺乳动物,我们通常会在动物园里看到:

public class Giraffe : Mammal
public class Rhinoceros : Mammal
public class Hippopotamus : Mammal

这仍然有效,因为Feed()和Mate()功能的核心仍然相同。

然而,长颈鹿、犀牛和河马并不是你可以用来做宠物的动物。这就是界面将有用的地方:

public interface IPettable
{
    IList<Trick> Tricks{get; set;}
    void Bathe();
    void Train(Trick t);
}

上述合同的执行在猫和狗之间是不同的;将它们的实现放在抽象类中继承将是一个坏主意。

狗和猫的定义现在应该如下:

public class Dog : Mammal, IPettable
public class Cat : Mammal, IPettable

理论上,您可以从更高的基类重写它们,但本质上,接口允许您只将所需的内容添加到类中,而不需要继承。

因此,由于您通常只能从一个抽象类继承(在大多数静态类型的OO语言中,即……例外包括C++),但能够实现多个接口,因此它允许您严格按照需要构造对象。

Josh Bloch在《有效的Java 2d》中说道:

首选接口而非抽象类

一些要点:

可以很容易地对现有类进行修改,以实现新的界面你所要做的就是添加所需的方法(如果还没有)存在并将implements子句添加到类声明。接口是定义混合的理想选择。粗略地说mixin是类可以使用的类型除了“主要”键入“”以声明它提供一些可选行为。例如Comparable是一个mixin接口允许类声明其实例的排序依据其他相互可比较的对象。接口允许构造非分层类型框架。类型层次结构为很适合组织一些事情,但是其他的事情并不是很简单刚性层次。接口通过每类包装的习惯用法。如果您使用抽象类来定义类型留下想要添加的程序员功能,别无选择使用继承。此外,你可以结合这些优点接口和抽象类提供抽象骨架实现类导出的非平凡接口。

另一方面,接口很难发展。如果您向接口添加一个方法,它将破坏它的所有实现。

PS:买这本书。它要详细得多。

通过def,接口提供了一个与其他代码通信的层。默认情况下,类的所有公共财产和方法都实现隐式接口。我们也可以将接口定义为一个角色,当任何类都需要扮演这个角色时,它必须实现它,根据实现它的类,给它不同的实现形式。oops的两个概念!!!

当我第一次开始学习面向对象编程时,我犯了一个简单的、可能也是常见的错误,即使用继承来共享公共行为——即使这种行为对对象的本质来说并不重要。

为了进一步建立这个问题中经常使用的例子,有很多东西都是可拍的——女朋友、汽车、毛毯所以我可能有一个Petable类提供了这种常见的行为,以及从中继承的各种类。

然而,可拍不是这些物体的本质的一部分。还有很多更重要的概念对他们的天性至关重要——女朋友是人,汽车是陆地车辆,猫是哺乳动物。。。

行为应该首先被分配给接口(包括类的默认接口),并且只有当它们(a)对于作为更大类的子集的一大群类来说是公共的时,才应该被提升为基类——在相同的意义上,“猫”和“人”是“哺乳动物”的子集。

问题是,当你比我一开始更了解面向对象设计之后,你通常会自动完成这项工作,甚至不用考虑它。因此,“代码到接口,而不是抽象类”这句话的真实性变得如此明显,你很难相信任何人都会不厌其烦地说出它,并开始尝试将其他含义解读到其中。

我想补充的另一点是,如果一个类是纯抽象的-没有非抽象的、非继承的成员或方法暴露给子级、父级或客户端-那么为什么它是一个类?它可以被替换,在某些情况下被接口替换,在其他情况下被Null替换。

基类的继承者应该具有“is a”关系。接口表示“实现”关系。因此,只有在继承者将维护关系时才使用基类。