在此处查看我的旧答案之一:
What is the advantage of using interfaces
这是我的一位教授曾经告诉我们的轶事。
长话短说,当您进入更复杂的系统时,您想要这样做的原因会变得更加清晰。将规范(接口/抽象类及其契约)与实现(具体类)分离的能力是一个强大的工具,它使得编写新实现变得非常容易,而无需在应用程序的其他地方更改代码。您在代码中使用规范,例如规范:
public interface Animal { ... }
你的实现:
public class Dog implements Animal { ... }
然后在代码中,尽可能使用规范:
Animal a = new Dog();
a.eat(); // All animals eat, so eat() is on the Animal interface
除非您绝对需要使用实现本身:
Dog d = new Dog();
d.bark(); // Other animals don't bark, so we need to have the Dog here
这使您的代码更简洁。例如,假设我有一个方法feedAndGroom。如果我没有接口,我需要为我想要支持的每种动物创建一个新方法:
public static void feedAndGroom(Cat c) { ... }
public static void feedAndGroom(Dog d) { ... }
public static void feedAndGroom(Turtle t) { ... }
根据具体情况,每个代码块甚至可能看起来完全相同。更糟糕的是,当有人发现一种新动物时会发生什么?我们每次都必须添加一个新方法,这将导致大量的方法。所有这些重复的解决方案是围绕功能创建一个接口,然后使用一个方法:
public static void feedAndGroom(Animal a) { ... }
这将采用任何实现Animal 接口的东西。所有这些方法调用都是合法的:
feedAndGroom(new Cat());
feedAndGroom(new Dog());
feedAndGroom(new Turtle());
不过,这些方法调用也是合法的:
feedAndGroom(new Hyena());
feedAndGroom(new Lion());
feedAndGroom(new Panther());
我们可能不想尝试喂养和梳理这些动物,至少不是野生动物,所以我们可以添加一个名为 DomesticatedAnimal 的新接口,扩展 Animal:
public interface `DomesticatedAnimal` extends `Animal` { ... }
并将我们的方法更改为:
public static void feedAndGroom(DomesticatedAnimal da) { ... }
然后,Dog、Cat 和 Turtle 类将实现 DomesticatedAnimal,而不是实现 Animal。例如:
public class Dog implements DomesticatedAnimal { ... }
这意味着Dog 既是一个DomesticatedAnimal,因为它直接实现了它,和一个Animal 通过继承自DomesticatedAnimal 扩展Animal。其他动物,Hyena、Lion 和Panther,只需实现Animal 接口。这意味着我们的新方法不会像原来的那样只使用任何Animal,而是将其限制为特定类型的Animal 对象。同时,使用原始Animal 接口编写的任何方法仍然适用于所有涉及的对象。