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

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

如果你要这样做

IInterface classRef = new ObjectWhatever()

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

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


当前回答

因此,为了做到这一点,接口的优点是我可以将方法的调用与任何特定的类分开。而是创建接口的实例,其中的实现来自我选择的实现该接口的任何类。因此,允许我拥有许多类,它们具有相似但略有不同的功能,并且在某些情况下(与接口的意图相关的情况)并不关心它是哪个对象。

例如,我可以有一个移动界面。一个方法可以让一些东西“移动”,任何实现移动接口的对象(Person, Car, Cat)都可以被传递进来并被告知移动。如果每个方法都不知道类的类型,那么它就是类。

其他回答

有很多解释,但让它更简单。以List为例。可以使用as实现一个列表:

内部数组 链表 其他实现

通过构建一个接口,比如一个List。您只编写了List的定义或List在实际中的含义。

你可以在内部使用任何类型的实现比如数组实现。但是假设您希望由于某种原因(比如bug或性能)更改实现。然后你只需要改变声明List<String> ls = new ArrayList<String>()为List<String> ls = new LinkedList<String>()。

在代码的其他地方,你不需要改变任何东西;因为其他所有东西都建立在List的定义之上。

你应该看看反转控制:

Martin Fowler:控制反转容器和依赖注入模式 维基百科:控制反转

在这种情况下,你不会这样写:

IInterface classRef = new ObjectWhatever();

你可以这样写:

IInterface classRef = container.Resolve<IInterface>();

这将进入容器对象中基于规则的设置,并为您构造实际对象,该对象可以是ObjectWhatever。重要的是,您可以将此规则替换为完全使用另一种类型对象的规则,而您的代码仍然可以工作。

如果我们不考虑IoC,那么您可以编写的代码知道它可以与执行特定操作的对象进行对话,但不知道是哪种类型的对象或它如何执行操作。

这将在传递参数时派上用场。

至于你带圆括号的问题“另外,你如何编写一个方法来接受一个实现接口的对象?”这可能吗?”,在c#中,你可以简单地使用接口类型作为参数类型,如下所示:

public void DoSomethingToAnObject(IInterface whatever) { ... }

这直接插入到“与做特定事情的对象对话”中。上面定义的方法知道从对象中期望得到什么,它实现了IInterface中的所有内容,但它并不关心它是哪种类型的对象,只关心它遵守契约,这就是接口。

例如,你可能对计算器很熟悉,也可能在你的生活中使用过不少计算器,但大多数时候它们都是不同的。另一方面,你知道标准计算器应该如何工作,所以你能够使用所有的计算器,即使你不能使用每个计算器都没有的特定功能。

这就是界面的美妙之处。你可以写一段代码,它知道它会得到传递给它的对象,它可以从这些对象中期待特定的行为。它并不关心它是什么类型的对象,只关心它支持所需的行为。

让我给你一个具体的例子。

我们为windows窗体定制了翻译系统。这个系统循环遍历表单上的控件,并翻译每个控件中的文本。这个系统知道如何处理基本的控件,比如拥有文本属性的控件类型,以及类似的基本东西,但对于任何基本的东西,它都做不到。

现在,由于控件继承自我们无法控制的预定义类,我们可以做以下三件事之一:

为我们的翻译系统提供支持,以检测它正在使用哪种类型的控件,并翻译正确的位(维护的噩梦) 将支持构建到基类中(不可能,因为所有控件都继承自不同的预定义类) 添加接口支持

所以是nr. 3。我们所有的控件都实现了ILocalizable,这是一个提供给我们一个方法的接口,能够将“本身”转换为翻译文本/规则的容器。因此,表单不需要知道它找到了哪种类型的控件,只需要知道它实现了特定的接口,并且知道可以调用某个方法来本地化该控件。

If you program in Java, JDBC is a good example. JDBC defines a set of interfaces but says nothing about the implementation. Your applications can be written against this set of interfaces. In theory, you pick some JDBC driver and your application would just work. If you discover there's a faster or "better" or cheaper JDBC driver or for whatever reason, you can again in theory re-configure your property file, and without having to make any change in your application, your application would still work.

下面是一个简单的示例,用于说明如何对航班预订系统进行编程。

//This interface is very flexible and abstract
    addPassenger(Plane seat, Ticket ticket); 

//Boeing is implementation of Plane
    addPassenger(Boeing747 seat, EconomyTicket ticket); 
    addPassenger(Cessna, BusinessClass ticket);


    addPassenger(J15, E87687); 

问:——……“你能使用任何实现接口的类吗?” A:是的。 问:——……“你什么时候需要这样做?” 答:-每次你都需要一个实现接口的类。

注意:我们不能实例化一个没有被类实现的接口- True。

为什么? 因为接口只有方法原型,没有定义(只有函数名,没有它们的逻辑)

AnIntf anInst = new class(); //我们可以这样做,只有当类实现AnIntf。 // anInst将有类引用。


注意:现在我们可以理解如果Bclass和Cclass实现相同的Dintf会发生什么。

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

我们拥有:相同的接口原型(接口中的函数名),调用不同的实现。

参考书目: 原型——维基百科