使用接口的好处是什么?

25

假设你有一个接口

public interface Change {

    void updateUser();
    void deleteUser();
    void helpUser();

}

我读过接口是Java实现多重继承的方式。你实现一个接口,然后就可以访问它的方法。但我不明白的是,这些方法在接口中都没有具体的内容,所以你需要在你的类中给它们一个具体的内容。如果一个接口被多个类实现,你需要在每个类中为该方法提供具体内容。那么相较于只在类中定义独立的方法而不实现接口,这样做有什么好处呢?


3
多态性是面向对象编程中的一个重要概念。它允许我们使用同一种类型的抽象实体来表示不同的具体实体,并能够以统一的方式处理它们。这种灵活性可以提高代码的可复用性和可维护性,同时也使得代码更加简洁易懂。在实践中,多态性通常通过继承和接口实现。 - Brian
1
当你开始设计一个库及其API时,你会发现接口非常有用,伙计 :) - user2511414
@NathanHughes 那个问题涉及到 PHP。(实际上,我想它更通俗地谈论了接口,但我仍然不会将其标记为该问题的重复)。 - arshajii
1
@arshajii:同意,我撤回了关闭投票。 - Nathan Hughes
2
在许多情况下,这是更好的选择,因为每个实现可能是完全不同的。我喜欢这个答案如何表达观点。使用接口比在多个类中实现一个方法要强大得多,因为如果每个类都实现相同的接口,则可以将它们全部视为相同的(无需转换)。这里有另一个答案,展示了一些利用接口的方法。 - jahroy
显示剩余2条评论
6个回答

64

我在大学的教授曾经讲过这个优秀的轶事来描述多态性和封装性。它是这样的。


这里有人知道自动售货机如何工作吗?(引起困惑的目光) 没有?那就让我告诉你。

您放入零钱,自动售货机内部有一个小猴子数着您的零钱,以确保您放足够的钱。当您按下所需饮料的按钮时,灯会亮起告诉小猴子您按下了哪个按钮,如果您投入了正确的金额,他会抓住您的选择并将其扔进小孔中,供您拿取饮料。

这就是封装的概念。我们隐藏了自动售货机的实现。除非它有那种高级的透明窗口让您看到内部,否则您完全不知道它是如何运作的。您只知道您放入一些现金,按下一个按钮,如果您投入足够的钱,您就能得到您想要的饮料。

此外,您知道如何使用自动售货机的接口,因此只要该机器的接口遵循通常的自动售货机接口,您就可以使用它。这称为接口契约。机器可以从南极洲通过传送带运来饮料,但只要您得到饮料、它凉爽并且您能拿回找零,您就无所谓了。

多态性是当您使用自动售货机接口时,它可能执行不同的操作的概念。这就是为什么封装和多态性密切相关的原因。在多态性中,您所知道的是您正在使用一个SodaMachine的实现,它可以更改,因此在幕后可以执行不同的操作。这导致多态性的驱动概念,即一个对象,SodaMachine,实际上可以充当MonkeySodaMachineConveyorSodaMachine,具体取决于实际接口后面的机器。


可能不是逐字翻译,但足够接近。实质上归结为两个概念:多态性封装性。如果需要澄清,请让我知道。


7
很好的比喻。接口让你能做的一件强大的事情是可以订购一卡车装满不同工作方式的饮料机,并将它们都放在同一个列表中。 - jahroy
如果每种不同类型的饮料都有多只猴子,例如xMonkey.java,yMonkey.java,那么这个比喻可能会更好。 - ralzaul
1
我觉得这个自动售货机的例子更与抽象有关。在我看来,我不知道。 - Charitha Goonewardena
1
@CharithaGoonewardena 在实际应用中,抽象、多态和封装是紧密相连的。如果您将一个实现封装起来,然后添加一层抽象,就可以实现多态性。换句话说,没有封装就没有抽象,没有抽象就没有多态性。添加一层抽象是实现多态性的关键。 - Brian
@Brian。明白了。谢谢你的信息。 - Charitha Goonewardena

14

为什么这比在类中只有个别方法,而没有实现接口更好?

因为如果一个类 C 实现了接口 I,你可以在需要 I 的任何地方使用 C。如果你不实现接口,即使你提供了接口要求的所有适当的方法,也不能这样做:

interface I {
    void foo();
}

class C1 implements I {
    public void foo() {
        System.out.println("C1");
    }
}

class C2 {  // C2 has a 'foo' method, but does not implement I
    public void foo() {
        System.out.println("C2");
    }
}

...

class Test {
    public static void main(String[] args) {
        I eye1 = new C1();  // works
        I eye2 = new C2();  // error!
    }
}

6
我有一个疑问,C2 myC2 = new C2; myC2.foo(); 肯定可以正常工作。那么使用接口有什么区别或好处呢? - Ebin Sebastian

10

它将调用方期望的东西与实现分离开来。你有一组纯净的方法可以调用,而不需要了解其实现。事实上,一些库(如JMS和JDBC)提供没有任何实现的接口。

这种分离意味着您不需要知道任何实际实现的类。


6
一个接口允许你保证某些方法存在并返回所需类型。当编译器知道这一点时,它可以使用该假设来处理未知的类,仿佛它们具有某些已知的行为。例如,比较接口保证实现类将能够对某些相似的对象进行compareTo()操作,并返回一个int值。
这意味着您可以比较任何实现了此接口的内容 - 因此,您可以对任何可比较对象进行排序,而无需编写一种方法来对字符串进行排序,另一种方法来对整数进行排序,还有一种方法来对带标签的书籍盒进行排序。

2

接口本质上保证了所有继承它的方法都将具有其方法,因此您可以安全地为任何继承它的内容调用接口中的方法。


0

使用接口定义API可以更容易地实现,这样接口的所有具体实现都会在每个类中提供所需的方法。

它还提供了一种实现多重继承的方式,在直接类继承中(在Java中)不可能实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接