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

Java 当只有一个实现类时,为什么要使用接口?,java,interface,implementation,Java,Interface,Implementation,我是编程新手,正在学习Java。 我只是想知道为什么我应该在只有一个实现类的情况下使用接口 接口可以由多个类实现。没有规定只有一个类可以实现这些。接口为java提供了抽象 您可以从此链接获取有关接口的更多信息您这样做是为了防止其他人访问您的实现类型。例如,您可以将实现类型隐藏在库中,授予类型包访问权限,并将接口的实例返回给库的用户: // This is what the users of your library know about the class // that does the w

我是编程新手,正在学习Java。
我只是想知道为什么我应该在只有一个实现类的情况下使用接口

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


您可以从此链接获取有关接口的更多信息

您这样做是为了防止其他人访问您的实现类型。例如,您可以将实现类型隐藏在库中,授予类型包访问权限,并将接口的实例返回给库的用户:

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

当实现使用大量库时,此技巧变得非常有用。您可以有效地将库的接口与其实现分离,这样用户就不必知道库内部的依赖关系。

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

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

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

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

class MyInterfaceImpl implements MyInterface {
  public void aMethod1() {...}
  public void aMethod2() {...}
}
您还有一个具有自己层次结构的不相关类:

public class SomeClass extends SomeOtherClass {
 ...
}
现在,您希望将
SomeClass
设置为
MyInterface
类型,但还希望继承
MyInterfaceImpl
中已经存在的所有代码。由于不能同时扩展
SomeOtherClass
MyInterfaceImpl
,因此可以实现接口并使用委派:

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

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

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

遵守接口隔离原则

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

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

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

要定义的类将实现这两个接口

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

  • 集合的单元测试必须使用实现可存储的对象编写,这增加了复杂性

  • 如果以后需要显示对象,则必须将显示代码所需的方法添加到单个接口,并修改收集和存储测试,以实现显示所需的方法


我在这里讨论对测试代码的影响。如果其他生产级对象需要存储而不需要显示,则问题更大。项目越大,不遵守接口隔离原则造成的问题就越大

我看不出给用户一个接口和给用户一个实现类之间有什么区别。“外观”是一样的…@Nitek:这里有一个这样解决的例子,OP想将公共方法公开给他不想向最终用户公开的测试:@Nitek这不是外观,这是关于将你的库的用户与他们不应该看到的东西隔离开来。不确定将测试方法公开然后试图隐藏它们是否是一种好的方式。我认为可能有一些情况可能是有意义的,但我认为这更像是一个边缘情况,然后是好的编程风格。也许值得说的是,还有很多情况下YAGNI是一个很好的默认……这是一个“链接唯一答案”,这被认为是StAcExcel上的坏形式,因为链接坏了。问问自己,如果没有链接,答案会有多好。除非你准备让答案足够独立,否则它应该是一个注释。我不认为提问者认为你只局限于一个实现类。我想他们更想知道为什么有人会在他们只有一个实现类的情况下拆分接口。重新打开,因为这个问题比所谓的重复要具体得多。请注意,如果有人对“所谓的重复”感兴趣,比如我: