当只有一个实现 class 时,为什么要使用接口?

Why should I use an interface when there is only one implementation class?

我是编程新手,正在学习 Java。 我只是想知道为什么只有一个实现 class 时我应该使用接口?

接口可以由多个 classes 实现。没有规定只有一个 class 可以实现这些。接口为 java 提供抽象。

http://www.tutorialspoint.com/java/java_interfaces.htm 您可以从此 link

获得有关接口的更多信息

您这样做是为了防止其他人访问您的实现类型。例如,您可以将您的实现类型隐藏在一个库中,为该类型提供包访问权限,并 return 向您的库用户提供您的接口实例:

// This is what the users of your library know about the class
// that does the work:
public interface SomeInterface {
    void doSomethingUseful();
    void doSomethingElse();
}

// This is the class itself, which is hidden from your clients
class MyImplementation implements SomeInterface {
    private SomeDependency dependency = new SomeDependency();
    public void doSomethingUseful() {
        ...
    }
    public void doSomethingElse() {
        ...
    }
}

您的客户获得这样的对象:

public class MyFactory {
    static SomeInterface make() {
        // MyFactory can see MyImplementation
        return new MyImplementation();
    }
}

当实现使用大量库时,这个技巧会很有用。您有效地将库的接口与其实现分离,这样用户就不必了解库内部的依赖关系。

一个原因是为了维护 open/closed 原则,该原则规定您的代码应该对扩展开放,但对修改关闭。尽管您现在只有一个实现 class,但随着时间的推移,您可能需要另一个不同的实现 class。如果事先将实现提取到接口中,则只需编写另一个实现 class 即。您不必修改完美工作的代码,消除引入错误的风险。

它可以让您在未来灵活地添加更多的实现,而无需更改引用该接口的客户端代码。

另一个有用的例子是在需要时在 Java 中模拟多重继承。例如,假设您有一个接口 MyInterface 和一个实现:

public interface MyInterface {
  void aMethod1();
  void aMethod2();
}

class MyInterfaceImpl implements MyInterface {
  public void aMethod1() {...}
  public void aMethod2() {...}
}

您还有一个不相关的 class,它有自己的层次结构:

public class SomeClass extends SomeOtherClass {
 ...
}

现在您想使 SomeClass 成为 MyInterface 类型,但您还想继承 MyInterfaceImpl 中已经存在的所有代码。由于不能同时扩展SomeOtherClassMyInterfaceImpl,所以可以实现接口并使用委托:

public class SomeClass extends SomeOtherClass implements MyInterface {
  private MyInterface myInterface = new MyInterfaceImpl();

  public void aMethod1() {
    myInterface.aMethod1();
  }

  public void aMethod2() {
    myInterface.aMethod2();
  }
  ...
}

遵守接口隔离原则。

创建接口的决定不应基于实现 classes 的数量,而应基于使用对象的不同方式的数量。对象的每种使用方式都由一个接口表示,该接口由使用它的代码定义。假设您的对象需要存储在内存中,存储在使对象保持有序的集合中。同样的对象也需要存储在一些持久存储中。

假设您首先实施持久性。存储系统需要的是持久化对象的唯一标识符。您使用方法 getUniqueId 创建一个接口,比如 Storable。然后您实施存储。

然后,您实施收集。您可以使用方法 compareTo 定义集合需要从接口中存储的对象中获取什么,例如 Comparable。然后,您可以实现依赖于 Comparable 的集合。

您要定义的 class 将实现这两​​个接口。

如果您定义的 class 实现单个接口,则该接口必须代表收集和存储系统的需要。这会导致,例如:

  • 集合的单元测试必须用实现可存储的对象编写,增加了一定程度的复杂性。

  • 如果后面需要显示对象,就需要在单一接口中添加显示代码需要的方法,修改采集和存储的测试,也实现需要的方法用于显示。

我这里说一下对测试代码的影响。如果其他生产级对象需要存储而不是显示,问题就更大了。项目越大,不遵守接口隔离原则所产生的问题就会越大。

我看到这篇 post 中提出了很多要点。也想将我的 2 美分添加到这个知识集合中。

接口鼓励在团队环境中进行并行开发。可以有2类个A和B,A调用B的API。可以有 2 个开发人员同时在 A 和 B 上工作。当 B 还没有准备好时,A 可以完全通过集成 B 的接口来实现自己的实现。

接口是在不同代码层之间建立API契约的良好基础。

将关注点与接口处理隐式 API 文档分开是件好事。参考一个并确定哪些 API 可供客户调用是非常容易的。

最后,最好在项目中练习使用接口作为标准,而不是必须根据具体情况(需要多个实现)来使用它。这确保了项目的一致性。

对于 Java 代码的艺术,界面使它们更加美丽:)

做任何事情都不能不经过思考和推理。

在某些情况下,您可能想要为单个实现添加一个接口...但 IMO 这是人们使用的旧 EJB 时代的过时实践并在没有适当推理和反思的情况下执行。

...Martin Fowler、Adan Bien 和其他人多年来一直这样说。

https://martinfowler.com/bliki/InterfaceImplementationPair.html

https://www.adam-bien.com/roller/abien/entry/service_s_new_serviceimpl_why