在我的开发学习中,我觉得我必须学习更多关于接口的知识。

我经常读到它们,但我似乎无法理解它们。

我读过这样的例子:动物基类,IAnimal接口的东西,如“Walk”,“Run”,“GetLegs”等-但我从来没有工作过,觉得“嘿,我应该在这里使用接口!”

我错过了什么?为什么这个概念对我来说这么难理解!我只是害怕这样一个事实,我可能从来没有意识到一个具体的需要-主要是由于一些缺失的理解他们!这让我觉得我作为一名开发人员缺少了一些东西!如果有人有过这样的经历,并取得了突破,我会很感激一些关于如何理解这个概念的建议。谢谢你!


当前回答

别太担心。很多开发人员很少需要编写接口。您将经常使用. net框架中可用的接口,但如果您觉得没有必要在短时间内编写一个接口,这也没什么好奇怪的。

我经常给别人的例子是,如果你有一个帆船职业和一个毒蛇职业。它们分别继承了Boat类和Car类。现在假设您需要遍历所有这些对象并调用它们的Drive()方法。你也可以编写如下代码:

if(myObject is Boat)
    ((Boat)myObject).Drive()
else
    if (myObject is Car)
        ((Car)myObject).Drive()

这样写会简单得多:

((IDrivable)myObject).Drive()

其他回答

I like Jimmy's answer a lot, but I feel I need to add something to it. The key to the whole thing is the "able" in IProcessable . It indicates a capability (or property, but meaning "intrinsic quality", not in the sense of C# properties) of the object that implements the interface. IAnimal is probably not a good example for an interface, but IWalkable might be a good interface to have if your system has many things that can walk. You might have classes derived from Animal such as Dog, Cow, Fish, Snake. The first two would probably implement IWalkable, the latter two don't walk, so they wouldn't. Now you ask "why not just have another superclass, WalkingAnimal, that Dog and Cow derive from?". The answer is when you have something completely outside the inheritance tree that also can walk, such as a robot. Robot would implement IWalkable, but probably wouldn't derive from Animal. If you want a list of things that can walk, you type it as IWalkable and you can put all walking animals plus robots in the list.

现在,将IWalkable替换为IPersistable这样更像软件的东西,这样的类比就更接近你在实际程序中看到的情况了。

当您希望能够对多个类型使用单个变量,但所有这些类型通过接口声明实现相同的方法时,Jimmy是正确的。然后你可以在接口类型变量上调用它们的main方法。

然而,使用接口还有第二个原因。当项目架构师和实现编码员是不同的人时,或者有几个实现编码员和一个项目经理。负责人可以编写一大堆接口,并查看系统的互操作,然后让开发人员用实现类填充接口。这是确保多人编写兼容类的最佳方法,而且他们可以并行地完成。

In my experience the driving force to create interfaces didn't occur until I start doing unit testing with a mocking framework. It became abundantly clear that using interfaces was going to make mocking much easier (since the framework depended on the methods being virtual). Once I started I saw the value of abstracting away the interface to my class from the implementation. Even if I don't create an actual interface, I try now to make my methods virtual (providing an implicit interface that can be overridden).

我发现还有许多其他原因可以加强重构到接口的良好实践,但是单元测试/模拟的事情提供了最初的“顿悟时刻”的实践经验。

EDIT: To clarify, with unit testing and mocking I always have two implementations -- the real, concrete implementation and an alternate mock implementation used in testing. Once you have two implementations, the value of the interface becomes obvious -- deal with it in terms of the interface so you can replace the implementation at any time. In this case I'm replacing it with a mock interface. I know that I can do this without an actual interface if my class is constructed properly, but using an actual interface reinforces this and makes it cleaner (clearer to the reader). Without this impetus, I don't think I would have appreciated the value of interfaces since most of my classes only, ever have a single concrete implementation.

当您希望定义对象可以显示的行为时,通常会使用接口。

在. net世界中,一个很好的例子是IDisposable接口,它用于任何使用必须手动释放的系统资源的Microsoft类。它要求实现它的类具有Dispose()方法。

Dispose()方法也被VB的using语言构造调用。NET和c#,只适用于IDisposables)

请记住,您可以通过使用诸如TypeOf…之类的构造来检查对象是否实现了特定的接口。Is (VB.NET), Is (c#), instanceof (Java),等等…

一个代码示例(结合了Andrew的代码和我的额外的关于“接口的目的是什么”的代码),也说明了为什么在不支持多重继承的语言(c#和java)上接口而不是抽象类:

interface ILogger
{
    void Log();
}
class FileLogger : ILogger
{
    public void Log() { }
}
class DataBaseLogger : ILogger
{
    public void Log() { }
}
public class MySpecialLogger : SpecialLoggerBase, ILogger
{
    public void Log() { }
}

注意,FileLogger和DataBaseLogger不需要接口(可以是Logger的抽象基类)。但是考虑到您需要使用第三方记录器,它迫使您使用基类(假设它公开了您需要使用的受保护的方法)。由于语言不支持多重继承,您将无法使用抽象基类方法。

底线是:尽可能使用接口来获得代码的额外灵活性。您的实现不那么受约束,因此它能更好地适应变化。