什么时候应该使用接口?

RKh*_*RKh 42 oop interface

我知道一个接口没有一个正文只是一个方法定义.但什么时候应该使用接口?如果我向某人提供一组没有正文的接口,为什么他们觉得需要编写函数体?他们最好用抽象方法编写自己的抽象类.

编辑:

我想当你是一个团队的一员时,使用Interfaces会更多.假设A队为某事写了一个代码,他们想看看是否调用了一个方法.使用名称getRecords(),是否完成.这将帮助B队编写提供给他们的界面的主体,B队必须保持方法名称相似,以便A队的代码运行.

只是一个想法.我可能错了.我认为Interfaces对单个开发人员没用.

编辑:

谢谢大家的答案.有了你们所回复的内容,我认为当你制作像API这样的东西时,接口有更多的用处?

tea*_*bot 53

在诸如Java和C#接口之类的语言中,提供了一种以多态方式拥有类的方法.也就是说一个类可以满足多个契约 - 它可以表现为多个不同的类型,一个类的类可以替代另一个类.在其他语言中,这也可以通过多重继承来提供,但是这种方法存在各种缺点.但是,让一个类表现为多个类型并不是使用接口的最常见动机.

通过编程到接口而不是类,您还可以将程序与特定实现分离.这使得将一个类实现替换为另一个类更容易.在编写单元测试时,这可能非常有用,您可能希望将一些重量级类实现与轻量级模拟对象交换.如果您的程序只需要一个接口类型,并且重量级对象和模拟对象都实现了所述接口,那么它们很容易替换.

另外,考虑一个简单的Java示例,我说有一个程序在屏幕上显示数据页面.最初我希望它从数据库或XML文件中获取数据.如果我编写我的程序以便它使用接口我可以定义一个接口,如下所示:

public interface PageDatasource {
    public List<Page> getPages();
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

PageDatasource datasource = // insert concrete PageDatasource implementation here
List<Pages> pages = datasource.getPages();
display(pages);
Run Code Online (Sandbox Code Playgroud)

然后,我可以编写符合此接口的单独数据库和XML实现:

public class DatabasePageDatasource implements PageDatasource {
    public List<Page> getPages() {
        // Database specific code
    }
}

public class XmlPageDatasource implements PageDatasource {
    public List<Page> getPages() {
        // XML specific code
    }
}
Run Code Online (Sandbox Code Playgroud)

因为我使用了一个接口,所以我现在可以互换地使用任一实现 - 数据库或XML - 而无需更改我的程序中要求页面数据的部分.XML和数据库实现可能完全不同,但我所关心的只是提供页面数据的对象实现了PageDatasource接口.


bha*_*atj 28

接口真实生活类比:

假设你想从图书馆发行一本书.你会做什么:
1)去图书馆
2)找到你感兴趣的书
3)选择书
4)去图书馆员台要求他们发行书.

现在这里Librarian是一个界面,这意味着你对图书馆员到底是谁不感兴趣,你只对那个坐在图书管理员桌面上的人感兴趣(是那个同意签订合同以担任图书管理员的人,这意味着那个人同意了实施图书馆员的所有行为)

所以说:图书馆员的行为是:
1)问题书
2)重新发行书
3)回归书.
被指定为图书馆员(意味着同意适应上述三种行为)的人必须以自己的方式实施这些行为.

假设PersonA想要扮演图书馆员的一部分,那么他需要适应上述3种行为.我们作为客户并不关心他是如何表现他的图书管理员行为的,我们只对那个人感兴趣,他是图书管理员,他会遵守图书馆员的任务.
因此,你将要做的是,参考接口[去图书馆员办公室(这将引导你作为图书管理员的人)]并且让我们说在未来一个人离开图书馆员的帖子,然后作为客户它不会影响你,如果你已经找到了图书管理员的办公桌,而不是作为图书馆员特定人员.所以代码接口而不是具体是有益的.

class PersonA implements Librarian {
    public void IssueBook(){...}
    public void ReIssueBook(){...}
    public void ReturnBook(){...}

    //Other person related tasks...
}   
Run Code Online (Sandbox Code Playgroud)


小智 10

即使单个开发人员界面也是一个非常有用的工具.让我试着用一个例子来说明.

假设您正在开发一个管理图书馆目录的系统,图书馆将借出书籍和DVD.您决定创建类BookDvd来模拟被借出的项目,但现在您想要实现多态性,以便您可以处理项目而不是书籍或DVD.问题是Item应该是抽象类还是接口?

在这种情况下,您可能希望使用抽象类,因为您可以通过父类提供BookDvd共有的功能,例如签出或返回项目.

现在假设您要为库目录实现持久性机制.您已决定要将某些数据存储在数据库中,将某些数据存储在XML文件中,将某些数据存储在逗号分隔的文件中.所以现在的问题是如何以多态方式实现这一点,以便您可以处理一般的持久性API?

在这种情况下,您可能应该定义一个接口,该接口可以由提供数据库,XML和逗号分隔持久性的每个类实现,因为每个持久性机制都提供类似的功能,即存储和检索数据,但每个都将以非常不同的方式实现.这将允许您轻松更改正在使用的持久性机制,而无需对使用持久性机制的代码进行大量更改.


Mik*_*son 8

接口有助于阐明不同功能单元之间的区别.一个单位取决于另一个单位上什么,不要一些东西.只要那个其他人可以界面中规定的(想想合同),那么它可以幕后的任何东西.

例如,我有一个入口处理器,它从一个地方读取条目,并将它们写入另一个地方.它不关心什么/在哪里,或在什么/哪里.所有它关心的是它从一些类型的阅读器(使用IReader接口)进入一侧,并将它们交给某种类型的编写器(使用IWriter接口).

在我的第一个实现中,IReader实现者从SQL数据库中获取内容,IWriter实现者通过Web服务客户端发布它.但是,我们最终会在两端创建其他实现者来访问其他存储库(FTP站点,本地网络驱动器上的文件目录等).

这一次中间的处理器并不关心也不会改变.它只是通过这些标准接口进行讨论.

从理论上讲,你可以使用一个基类(最好是一个抽象的基类)而不是一个接口,但这会开始将你的模块更紧密地锁在一起,这使你的系统更难维护.即使你不是一个程序员团队,失去耦合确实会让你的生活变得更轻松.每次在系统的不同部分工作时,请将自己视为不同的程序员.每次重新访问给定的部分时,您都必须重新学习它所做的工作以维护它.如果你的系统的每个部分都与其他部分紧密耦合,那么你必须对整个系统有一个恒定,深入的了解,而不仅仅是你正在工作的那个部分.

还有一个实现多个接口的单个​​类的概念,这几乎就像多重继承.在这种情况下,单个班级可以执行多个工作(可以说这不是很明智,但至少可以这样做).如果您选择使用基类而不是上面的接口,那么这是不可能的.


tob*_*int 7

乍一看,抽象类和接口看起来很简单.为什么只提供一个接口,你还可以提供一些基础实现?经过调查,你会发现还有更多.

也就是说,使用接口有很多原因.你可以在这里找到关于差异的体面博客文章.

也就是说,考虑一下你可以创建一个接口(一个"契约",表示你的类肯定支持某些调用/方法签名调用),但你只能提供一个抽象类.还要考虑这样一个事实,即您可以创建一个也实现一个或多个接口的抽象类,并从中继承.这不是边缘情况.实际上,这在API中经常用于高可扩展性.

看看我指出的博客文章,你应该彻底了解何时使用它们以及为什么要使用它们.我还强烈推荐一本好书,例如Microsoft Press的"CLR via C#".你会学到很多东西!


And*_*ith 7

接口存在的原因是由于OOP的两个原则概念,即"身份"和"功能"

类具有功能和身份.通过继承,实例化的对象可以具有许多功能和多个身份.

接口是没有功能的标识.该功能将由实例化的类提供.

第三种形式,"mixin"是没有身份的功能.像ruby这样的编程语言提供了第三种继承形式.

如何使用接口因编程语言的上下文和环境而异,但请记住,接口用于定义强制执行到对象的标识.