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

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

如果你要这样做

IInterface classRef = new ObjectWhatever()

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

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


当前回答

接口类似于契约,您希望实现类实现在契约(接口)中编写的方法。由于Java不提供多重继承,“编程到接口”是实现多重继承的好方法。

如果您有一个类a,它已经扩展了其他一些类B,但是您希望这个类a也遵循某些指导方针或实现某个契约,那么您可以通过“编程到接口”策略来实现。

其他回答

问:——……“你能使用任何实现接口的类吗?” 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.

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

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

它也适用于单元测试,你可以将你自己的类(满足接口的要求)注入到依赖它的类中

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.

短篇故事:一个邮递员被要求挨家挨户地接收写有地址的信封(信件、文件、支票、礼品卡、申请书、情书)。

假设没有封面,让邮递员挨家挨户地接收所有的东西,然后交给其他人,邮递员会感到困惑。

所以最好用封面(在我们的故事中是接口)包装它,然后他就会很好地完成他的工作。

现在邮差的工作只是收和送封皮(他不关心封皮里面有什么)。

创建一个接口类型,而不是实际类型,而是使用实际类型实现它。

创建一个接口意味着你的组件可以很容易地适应其余的代码

我给你们举个例子。

你有一个plane界面,如下所示。

interface Airplane{
    parkPlane();
    servicePlane();
}

假设在平面的Controller类中有这样的方法

parkPlane(Airplane plane)

and

servicePlane(Airplane plane)

在您的程序中实现。它不会破坏你的代码。 我的意思是,只要它接受参数plane,它就不需要改变。

因为它将接受任何飞机,不管实际类型,飞行员,高空飞行,战斗机等。

同样,在集合中:

列表> <飞机飞机;//会占用你所有的飞机。

下面的例子将帮助您理解。


你有一架战斗机来执行它,所以

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

HighFlyer和其他类也是如此:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

现在假设你的控制器类多次使用AirPlane,

假设你的控制器类是ControlPlane,如下所示,

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

神奇的是,你可以在不改变ControlPlane类代码的情况下,尽可能多地创建新的AirPlane类型实例。

你可以添加一个实例…

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

您也可以删除以前创建的类型的实例。

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

// 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());
    }
}