我应该何时使用接口,何时使用基类?
如果我不想实际定义方法的基本实现,它应该始终是一个接口吗?
如果我有狗和猫的课。为什么我要实现IPet而不是PetBase?我可以理解为ISheds或IBarks(IMakesNoise?)提供接口,因为它们可以逐个宠物放置,但我不知道该为普通宠物使用哪个接口。
我应该何时使用接口,何时使用基类?
如果我不想实际定义方法的基本实现,它应该始终是一个接口吗?
如果我有狗和猫的课。为什么我要实现IPet而不是PetBase?我可以理解为ISheds或IBarks(IMakesNoise?)提供接口,因为它们可以逐个宠物放置,但我不知道该为普通宠物使用哪个接口。
当前回答
Josh Bloch在《有效的Java 2d》中说道:
首选接口而非抽象类
一些要点:
可以很容易地对现有类进行修改,以实现新的界面你所要做的就是添加所需的方法(如果还没有)存在并将implements子句添加到类声明。接口是定义混合的理想选择。粗略地说mixin是类可以使用的类型除了“主要”键入“”以声明它提供一些可选行为。例如Comparable是一个mixin接口允许类声明其实例的排序依据其他相互可比较的对象。接口允许构造非分层类型框架。类型层次结构为很适合组织一些事情,但是其他的事情并不是很简单刚性层次。接口通过每类包装的习惯用法。如果您使用抽象类来定义类型留下想要添加的程序员功能,别无选择使用继承。此外,你可以结合这些优点接口和抽象类提供抽象骨架实现类导出的非平凡接口。
另一方面,接口很难发展。如果您向接口添加一个方法,它将破坏它的所有实现。
PS:买这本书。它要详细得多。
其他回答
通过def,接口提供了一个与其他代码通信的层。默认情况下,类的所有公共财产和方法都实现隐式接口。我们也可以将接口定义为一个角色,当任何类都需要扮演这个角色时,它必须实现它,根据实现它的类,给它不同的实现形式。oops的两个概念!!!
让我们以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++),但能够实现多个接口,因此它允许您严格按照需要构造对象。
首选接口而非抽象类
根本原因需要考虑的要点[这里已经提到了两个]是:
接口更灵活,因为一个类可以实现多个接口。由于Java没有多重继承,因此使用抽象类防止用户使用任何其他类等级制度通常,当没有默认值时,首选接口实现或状态。Java集合提供了这(地图、集合等)。抽象类的优点是允许更好的转发兼容性。一旦客户端使用了一个接口,就不能更改它;如果它们使用抽象类,您仍然可以添加行为而不使用破坏现有代码。如果兼容性是一个问题,请考虑使用抽象类。即使您有默认实现或内部状态,考虑提供一个接口及其抽象实现。这将有助于客户,但如果所需[1]。当然,这个问题已经讨论了很长时间其他地方[2,3]。
[1] 当然,它增加了更多的代码,但如果简洁是您的主要关注点,那么您可能应该首先避免使用Java!
[2] Joshua Bloch,《有效的Java》,第16-18项。
[3] http://www.codeproject.com/KB/ar...
现代风格是定义IPet和PetBase。
该接口的优点是其他代码可以使用它,而与其他可执行代码没有任何联系。完全“干净”。界面也可以混合。
但是基类对于简单的实现和通用实用程序很有用。因此,还提供一个抽象基类,以节省时间和代码。
我通常在需要之前都不会实现。与抽象类相比,我更喜欢接口,因为这提供了更多的灵活性。如果在某些继承类中有共同的行为,我会将其上移并创建一个抽象基类。我不认为两者都有必要,因为它们本质上服务于相同的目的,而且两者都有一种糟糕的代码气味(imho),解决方案被过度设计了。