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

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

如果你要这样做

IInterface classRef = new ObjectWhatever()

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

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


当前回答

program to an interface is a term from the GOF book. i would not directly say it has to do with java interface but rather real interfaces. to achieve clean layer separation, you need to create some separation between systems for example: Let's say you had a concrete database you want to use, you would never "program to the database" , instead you would "program to the storage interface". Likewise you would never "program to a Web Service" but rather you would program to a "client interface". this is so you can easily swap things out.

我发现这些规则对我很有帮助:

1. 当我们有多种类型的对象时,我们使用Java接口。如果我只有一个对象,我就看不到意义了。如果某个想法至少有两种具体实现,那么我会使用Java接口。

2. 如果如上所述,您希望从外部系统(存储系统)到自己的系统(本地DB)进行解耦,那么也需要使用接口。

注意有两种方法来考虑何时使用它们。

其他回答

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

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

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

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

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

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

我给你们举个例子。

你有一个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.

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

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

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

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

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

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

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

为一个界面编码是一种哲学,而不是特定的语言结构或设计模式——它指导你为了创建更好的软件系统而遵循正确的步骤顺序(例如,更有弹性,更可测试,更可伸缩,更可扩展,以及其他良好的特性)。

它的实际意思是:

===

在跳到实现和编码(如何)之前,先想想是什么:

你的系统中应该有哪些黑箱, 每个盒子的职责是什么? 每个“客户端”(即其他盒子,第三方“盒子”,甚至人类)应该与它(每个盒子的API)通信的方式是什么?

在你理清上面的问题之后,继续执行这些方框(HOW)。

首先考虑什么是盒子,什么是它的API,这将引导开发人员提炼盒子的职责,并为自己和未来的开发人员标记它的公开细节(“API”)和隐藏细节(“实现细节”)之间的区别,这是一个非常重要的区别。

一个直接且容易注意到的收获是,团队可以在不影响总体架构的情况下更改和改进实现。它还使系统更具可测试性(它与TDD方法配合得很好)。

= = = 除了我上面提到的特质,你还可以在这个方向上节省很多时间。

微服务和DDD,如果做得正确,是“编码到接口”的很好的例子,然而这个概念在每个模式中获胜,从巨石到“无服务器”,从BE到FE,从面向对象到功能性,等等....

我强烈推荐这种方法用于软件工程(我基本上相信它在其他领域也完全有意义)。