Java接口方法:每个类应该实现一个接口吗?

我一直在Java中为大学的一些课程编程,我有以下问题:

从方法论上接受每个类应该实现一个接口吗? 不这样做被认为是不好的做法吗? 你能描述一下使用接口不是一个好主意的情况吗?

编辑:就个人而言,我喜欢将接口用作一种方法和习惯的概念,即使它不是明显有益的。 Eclipse自动创建了一个包含所有方法的类文件,因此它不会浪费任何时间。

如果您不打算使用它,则无需创建界面。

通常,在以下情况下需要接口:

  • 您的程序将为您的组件提供多种实现。 例如,作为代码一部分的默认实现,以及在JUnit测试中使用的模拟实现。 有些工具可以自动创建模拟实现,例如EasyMock。
  • 您希望对此类使用dependency injection,使用Spring或JBoss Micro-Container等框架。 在这种情况下,最好使用接口从一个类和其他类指定依赖项。

遵循YAGNI原则,如果您真的需要,类应该实现接口。 否则你从中获得了什么?

编辑:接口提供了一种抽象。 如果要在不同的实现(实现相同接口的许多类)之间进行交换,它们特别有用。 如果它只是一个单一的类,那么就没有收获。

每个类都实现了一个接口(即契约),因为它提供了非私有API。 是否应该选择将接口单独表示为Java接口取决于实现是否是“变化的概念”。

如果您完全确定只有一个合理的实现,那么就不需要接口。 否则,接口将允许您在不更改客户端代码的情况下更改实现。

有些人会喊“YAGNI”,假设如果您以后发现新的要求,您可以完全控制更改代码。 其他人会非常害怕他们需要改变不可更改的 – 一个已发布的API。

如果你没有实现一个接口(并使用某种工厂来创建对象),那么某些类型的更改将迫使你打破开闭原则。 在某些情况下,这是商业上可接受的,而在其他情况下则不是。

你能描述一下使用接口不是一个好主意的情况吗?

在某些语言(例如C ++,C#,但不是Java)中,如果您的类不包含虚拟方法,则可以获得性能优势。

在小程序或没有已发布API的应用程序中,您可能会看到维护单独接口的成本很低。

如果由于分离接口和实现而导致复杂性显着增加,那么您可能不会将接口用作合同。 接口降低了复杂性。 从消费者的角度来看,组件成为履行合同条款的商品,而不是具有本身具有复杂实施细节的实体。

不,每个类都没有必要实现接口。 仅在使代码更清晰且更易于编写时才使用接口。

如果您的程序目前不需要为给定的类实现多于1个实现,那么您不需要接口。 例如,在我写的一个简单的国际象棋程序中,我只需要一种类型的Board对象。 棋盘是棋盘棋盘。 制作一个Board接口并实现它只需要更多的代码来编写和维护。

如果你最终需要它,那么切换到界面是如此容易。

不必为每个类创建接口。 一些常被引用的原因包括模拟(不需要像Mockito这样的现代模拟框架)和dependency injection(例如Spring,现代实现中也不需要)。

如果需要,创建一个接口,特别是正式记录公共接口。 有几个漂亮的边缘情况(例如标记接口)。

值得一提的是,在最近的一个项目中,我们使用了所有接口(DI和模拟被引用作为原因),结果certificate它是完全浪费并增加了很多复杂性 – 在添加接口时同样容易实际上需要在极少数情况下嘲笑它。 最后,我确信有人会在某个周末进入并删除所有无关的界面。

我注意到C程序员首先转向Java往往喜欢很多接口(“它就像标题”)。 当前版本的Eclipse支持此function,允许通过控件单击导航生成弹出窗口,询问接口或实现。

我发现在相应的接口中定义类的公共方法是有益的,并且在定义对其他类的引用时严格使用接口引用。 这样可以轻松反转控制,并且还可以通过模拟和存根进行unit testing。 它还为您提供了使用其他实现该接口的类替换实现的自由,因此,如果您使用TDD,它可能会使事情变得更容易(或者如果您是TDD的批评者则更加做作)

接口是获取多态性的方法。 因此,如果您只有一个实现,一个特别类型的类,则不需要接口。

以非常生硬的方式回答OP的问题:不,并非所有类都需要实现接口。 就像所有设计问题一样,这归结为一个人的最佳判断。 以下是我通常遵循的一些规则:

  • 纯粹的function对象可能不需要(例如Pattern,CharMatcher – 即使后者确实实现谓词,它是其核心function的次要)
  • 纯数据持有者可能不需要(例如LogRecord,Locale)
  • 如果您可以设想给定function的不同实现(例如,内存中缓存与基于磁盘的缓存),请尝试将function隔离到接口中。 但也不要试图预测未来。
  • 出于测试目的,当执行I / O或启动线程的类很容易模拟时非常方便,因此用户在运行测试时不会支付罚金。
  • 没有什么比泄漏其底层实现的接口更糟糕了。 注意绘制线条的位置,并确保界面的Javadoc以这种方式保持中立。 如果不是,您可能不需要界面。
  • 一般来说,最好是在您的软件包/项目之外用于公共消费的类来实现接口,这样您的用户就可以更少地与您的实现相结合。

请注意,您可以找到该列表中每个项目符号的反例。 接口非常强大,因此需要小心使用和创建它们,特别是如果您提供外部API(观看此video以说服自己)。 如果你太快地将界面放在所有东西面前,你可能最终会泄漏你的单一实现,而你只会让跟随你的人变得更复杂。 如果你没有足够使用它们,你最终可能会得到一个同样难以维护的代码库,因为一切都是静态绑定的,很难改变。 上面的非详尽列表是我尝试绘制线的地方。

学习被认为是好的方法的好方法,特别是在代码结构设计方面,是考虑免费提供的代码。 使用Java,显而易见的例子是查看JDK系统库 。

您将找到许多未实现任何接口的类的示例,或者可以直接使用的类,例如java.util.StringTokenizer。

如果在应用程序接口中使用服务提供程序接口模式,则比抽象类更难扩展。 如果向接口添加方法,则必须重写所有服务提供者。 但是,如果将非抽象方法添加到抽象类,则不必重写任何服务提供者。

如果只有一小部分接口方法通常具有有意义的实现,那么接口也会使编程更加困难。

当我从头设计一个新系统时,我使用面向组件的方法,每个组件(10个或更多类)提供一个接口,这允许我(有时)重用它们。

  • 在设计工具(或简单的系统)时,我认为这不一定是可扩展的框架,当我需要第二个实现作为选项时,我会引入接口。

  • 我看到一些产品通过界面暴露了几乎所有function,只花了太多时间来理解不必要的复杂性。

接口就像服务提供者(服务器)和这种服务(客户端)的用户之间的契约。

  • 如果我们正在开发Web服务并且我们通过控制器类公开其余路由,则控制器类可以实现接口,并且这些接口充当Web服务与使用此Web服务的其他应用程序之间的协议。
  • SerializableClonnableRemote这样的Java接口用于向编译器或JVM指示内容。当JVM看到实现这些接口的类时,它会对其执行某些操作以支持序列化,克隆或远程方法调用。 如果您的类需要这些function,那么您将必须实现这些接口。

使用Interface即将使您的应用程序框架适应变化。 因为正如我在这里提到的( 多重inheritance争论II:根据Stroustrup )在java和c#中取消了多重inheritance,我很遗憾,应该总是使用Interface,因为你永远不知道未来会是什么。