Почему я должен использовать интерфейс, если существует только один класс реализации?

Я новичок в программировании, и я изучаю Java. Мне просто интересно, почему я должен использовать интерфейс, когда есть только один класс реализации?

Ответ 1

Вы делаете это, чтобы другие не могли получить доступ к вашему типу реализации. Например, вы можете скрыть свой тип реализации внутри библиотеки, предоставить доступ к типу пакета и вернуть экземпляр вашего интерфейса пользователям вашей библиотеки:

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

Этот трюк становится полезным, когда реализация использует множество библиотек. Вы эффективно отключаете интерфейс своей библиотеки от ее реализации, чтобы пользователю не нужно было знать о зависимостях, внутренних для вашей библиотеки.

Ответ 2

Одна из причин заключается в поддержании принципа open/closed, который гласит, что ваш код должен быть открыт для расширения, но закрыт для модификации. Хотя у вас есть только один класс внедрения, вероятность того, что вам понадобится другой класс реализации с течением времени. Если вы предварительно извлечете реализацию в интерфейс, вам просто нужно написать другой класс реализации, т.е. Вам не нужно модифицировать отлично работающий фрагмент кода, устраняя риск появления ошибок.

Ответ 3

Он может предоставить вам гибкость для добавления дополнительных реализаций в будущем без изменения кода клиента, который ссылается на интерфейс.

Другим примером того, когда может быть полезно, является симуляция множественного наследования в 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();
  }
  ...
}

Ответ 4

Соблюдать принцип разделения интерфейса.

Решение о создании интерфейса не должно основываться на количестве реализующих классов, а скорее на количестве различных способов использования этого объекта. Каждый способ использования объекта представлен интерфейсом, определенным с помощью кода, который его использует. Скажите, что ваш объект должен храниться в памяти, в коллекциях, которые хранят объекты в порядке. Тот же объект, а также должен храниться в некотором постоянном хранилище.

Предположим, что вы сначала выполняете персистентность. То, что требуется системе хранения, является уникальным идентификатором для сохраняемых объектов. Вы создаете интерфейс, например Storable, с помощью метода getUniqueId. Затем вы реализуете хранилище.

Затем вы реализуете коллекцию. Вы определяете, что коллекция требует от хранимых объектов в интерфейсе, например Comparable, с методом compareTo. Затем вы можете реализовать коллекцию с зависимостью от Comparable.

Класс, который вы хотите определить, будет реализовывать оба интерфейса.

Если класс, который вы определяете, реализует единый интерфейс, этот интерфейс должен будет представлять потребности системы сбора и хранения. Это вызовет, например:

  • модульные тесты для коллекции должны быть записаны с объектами, которые реализуют Storable, добавляя уровень сложности.

  • Если возникнет необходимость позже отобразить объект, вам придется добавить методы, необходимые для отображения кода, в один интерфейс и изменить тесты для сбора и хранения, чтобы также реализовать методы, необходимые для отображения.

Я говорю о влиянии на тестовый код здесь. Проблема больше, если другие объекты уровня производства нуждаются в хранении и не отображаются. Чем больше проект, тем больше будет проблема, созданная несоблюдением принципа разделения сегрегации.

Ответ 5

Интерфейсы могут быть реализованы несколькими классами. Нет правила, что только один класс может их реализовать. Интерфейсы обеспечивают абстракцию java.

http://www.tutorialspoint.com/java/java_interfaces.htm Вы можете получить дополнительную информацию об интерфейсах из этой ссылки.