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

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

如果你要这样做

IInterface classRef = new ObjectWhatever()

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

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


当前回答

编程到接口允许无缝地改变由接口定义的契约的实现。它允许契约和特定实现之间的松耦合。

IInterface classRef = new ObjectWhatever() 你可以使用任何实现IInterface的类吗?你什么时候需要这样做?

看看这个SE问题的好例子。

为什么应该首选Java类的接口?

使用接口会影响性能吗? 如果有,多少钱?

是的。它将在几秒内产生轻微的性能开销。但是如果您的应用程序需要动态地更改接口的实现,则不必担心性能影响。

如何避免这种情况而不需要维护两段代码呢?

如果您的应用程序需要多个接口实现,不要试图避免它们。在接口与某个特定实现缺乏紧密耦合的情况下,您可能必须部署补丁以将一个实现更改为另一个实现。

一个好的用例:Strategy模式的实现:

策略模式的真实例子

其他回答

当您拥有一组类似的类时,它使您的代码更具可扩展性,更容易维护。我是一个初级程序员,所以我不是专家,但我刚刚完成了一个需要类似东西的项目。

我从事与运行医疗设备的服务器对话的客户端软件工作。我们正在开发这种设备的新版本,其中有一些新组件,客户必须不时进行配置。有两种类型的新组件,它们是不同的,但也非常相似。基本上,我必须创建两个配置表单,两个列表类,所有东西都要创建两个。

我决定最好是为每个控件类型创建一个抽象基类,它可以容纳几乎所有的实际逻辑,然后是派生类型,以处理两个组件之间的差异。然而,如果我不得不一直担心类型,基类就不能在这些组件上执行操作(好吧,它们可以,但每个方法中都有一个“if”语句或开关)。

我为这些组件定义了一个简单的接口,所有基类都与该接口对话。现在当我改变一些东西,它几乎“只是工作”在任何地方,我没有代码复制。

此外,我在这里看到了很多很好的解释性答案,所以我想在这里给出我的观点,包括一些我在使用这种方法时注意到的额外信息。

单元测试

在过去的两年里,我写了一个业余项目,但我没有为它写单元测试。在写了大约50K行代码后,我发现编写单元测试是非常必要的。 我没有使用接口(或者很少使用)……当我做第一个单元测试时,我发现它很复杂。为什么?

因为我必须创建大量的类实例,用作类变量和/或参数的输入。所以测试看起来更像集成测试(必须制作一个完整的类“框架”,因为所有的类都捆绑在一起)。

界面恐惧 所以我决定使用接口。我担心的是我必须在所有地方(在所有使用的类中)多次实现所有功能。在某种程度上,这是正确的,然而,通过使用继承,它可以减少很多。

接口和继承的组合 我发现这个组合很好用。我举一个非常简单的例子。

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

这样就不需要复制代码,同时仍然有使用汽车作为接口(ICar)的好处。

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

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

内部数组 链表 其他实现

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

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

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

听起来好像你知道接口是如何工作的,但不确定何时使用它们以及它们提供了什么优势。下面是几个例子,说明界面是有意义的:

// if I want to add search capabilities to my application and support multiple search
// engines such as Google, Yahoo, Live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

然后我可以创建GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider等。

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

然后创建JpegImageLoader, GifImageLoader, PngImageLoader等。

大多数外接程序和插件系统都离不开接口。

另一种流行的用法是Repository模式。假设我想从不同的来源加载一个邮政编码列表

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

然后我可以创建一个XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository等。对于我的web应用程序,我经常在早期创建XML存储库,这样我就可以在SQL数据库准备好之前启动并运行一些东西。一旦数据库准备好了,我就编写一个SQLRepository来替换XML版本。我的其余代码保持不变,因为它完全基于接口运行。

方法可以接受如下接口:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}