我曾多次看到有人提到这一点,但我不清楚这是什么意思。你什么时候,为什么要这么做?

我知道接口是做什么的,但我不清楚这一点的事实使我认为我错过了正确使用它们。

如果你要这样做

IInterface classRef = new ObjectWhatever()

你可以使用任何实现IInterface的类吗?你什么时候需要这样做?我能想到的唯一一件事是,如果你有一个方法,你不确定什么对象将被传递,除了它实现IInterface。我不知道你需要多久做一次。

另外,如何编写一个方法来接受实现接口的对象呢?这可能吗?


当前回答

假设你有一个名为“Zebra”的产品,可以通过插件进行扩展。它通过在某个目录中搜索dll来查找插件。它加载所有这些dll,并使用反射来查找实现IZebraPlugin的任何类,然后调用该接口的方法来与插件通信。

这使得它完全独立于任何特定的插件类——它不关心类是什么。它只关心它们是否满足接口规范。

接口是这样定义可扩展性点的一种方式。与接口对话的代码是松散耦合的——事实上,它与任何其他特定的代码根本不耦合。它可以与多年后由从未见过原始开发人员的人编写的插件进行互操作。

你可以使用一个带有虚函数的基类——所有的插件都是从基类派生的。但这有很大的限制,因为一个类只能有一个基类,而它可以实现任意数量的接口。

其他回答

为了补充现有的帖子,当开发人员同时在不同的组件上工作时,有时对接口进行编码有助于大型项目。您所需要做的就是预先定义接口并为它们编写代码,而其他开发人员则为您正在实现的接口编写代码。

接口编程与我们在Java或。net中看到的抽象接口完全没有关系。它甚至不是面向对象的概念。

它的意思是不要乱动对象或数据结构的内部结构。使用抽象程序接口(API)与数据交互。在Java或c#中,这意味着使用公共属性和方法,而不是原始字段访问。对于C语言来说,这意味着使用函数而不是原始指针。

EDIT:对于数据库,这意味着使用视图和存储过程,而不是直接访问表。

如果我正在编写一个新类Swimmer来添加swim()功能,并且需要使用类的对象说Dog,并且这个Dog类实现了声明swim()的接口Animal。

在层次的顶端(动物),它是非常抽象的,而在底层(狗),它是非常具体的。我认为“面向接口编程”的方式是,当我编写Swimmer类时,我想针对层次结构最高的接口编写代码,在本例中是Animal对象。接口没有实现细节,因此使代码松耦合。

实现细节可以随着时间的推移而改变,但是,它不会影响剩余的代码,因为您所与之交互的是接口而不是实现。你不关心实现是什么样的……您所知道的是,将会有一个实现该接口的类。

面向接口而不是实现的代码与Java无关,也与它的接口构造无关。

这个概念是在模式/四人帮的书中突出的,但很可能在那之前就已经存在了。这个概念在Java出现之前就已经存在了。

Java Interface构造的创建就是为了帮助实现这一想法(以及其他一些事情),人们过于关注作为意义中心的构造,而不是最初的意图。然而,这也是为什么我们在Java、c++、c#等语言中有公共和私有方法和属性的原因。

It means just interact with an object or system's public interface. Don't worry or even anticipate how it does what it does internally. Don't worry about how it is implemented. In object-oriented code, it is why we have public vs. private methods/attributes. We are intended to use the public methods because the private methods are there only for use internally, within the class. They make up the implementation of the class and can be changed as required without changing the public interface. Assume that regarding functionality, a method on a class will perform the same operation with the same expected result every time you call it with the same parameters. It allows the author to change how the class works, its implementation, without breaking how people interact with it.

And you can program to the interface, not the implementation without ever using an Interface construct. You can program to the interface not the implementation in C++, which does not have an Interface construct. You can integrate two massive enterprise systems much more robustly as long as they interact through public interfaces (contracts) rather than calling methods on objects internal to the systems. The interfaces are expected to always react the same expected way given the same input parameters; if implemented to the interface and not the implementation. The concept works in many places.

不要认为Java接口与“面向接口编程,而不是面向实现”的概念有什么关系。它们可以帮助应用概念,但它们不是概念。

这里有一些关于这个问题的很好的答案,涉及到各种关于接口和松耦合代码、控制反转等等的细节。有一些相当令人兴奋的讨论,所以我想借此机会把事情分解一下,以理解为什么界面是有用的。

When I first started getting exposed to interfaces, I too was confused about their relevance. I didn't understand why you needed them. If we're using a language like Java or C#, we already have inheritance and I viewed interfaces as a weaker form of inheritance and thought, "why bother?" In a sense I was right, you can think of interfaces as sort of a weak form of inheritance, but beyond that I finally understood their use as a language construct by thinking of them as a means of classifying common traits or behaviors that were exhibited by potentially many non-related classes of objects.

例如,假设你有一款SIM游戏,并拥有以下类:

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

显然,这两个对象在直接继承方面没有任何共同之处。但是,你可以说它们都很烦人。

让我们假设我们的游戏需要有一些随机的东西让玩家在吃饭时感到厌烦。这可以是HouseFly或Telemarketer,或两者兼而有之,但你如何在一个功能上兼顾两者呢?你如何要求每个不同类型的对象以同样的方式“做他们讨厌的事情”?

要认识到的关键是,Telemarketer和HouseFly都共享一个共同的松散解释的行为,尽管它们在建模方面完全不同。所以,让我们创建一个两者都可以实现的接口:

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

我们现在有两个类,每个类都以自己的方式令人讨厌。它们不需要派生于相同的基类,也不需要共享共同的固有特征——它们只需要满足IPest的契约——这个契约很简单。你只需要变得烦人。在这方面,我们可以建立以下模型:

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

这里我们有一个餐厅,可以接待许多食客和一些害虫——注意界面的使用。这意味着在我们的小世界中,害虫数组的成员实际上可以是Telemarketer对象或HouseFly对象。

The ServeDinner method is called when dinner is served and our people in the dining room are supposed to eat. In our little game, that's when our pests do their work -- each pest is instructed to be annoying by way of the IPest interface. In this way, we can easily have both Telemarketers and HouseFlys be annoying in each of their own ways -- we care only that we have something in the DiningRoom object that is a pest, we don't really care what it is and they could have nothing in common with other.

这个非常人为的伪代码示例(比我预期的要长得多)只是为了说明一些事情,这些事情最终为我打开了一盏灯,让我知道什么时候可以使用接口。我为这个例子的愚蠢提前道歉,但希望它有助于您的理解。而且,可以肯定的是,您在这里收到的其他回答确实涵盖了当今在设计模式和开发方法中使用接口的全部范围。