Конструктор в интерфейсе?

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

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

Например, рассмотрим следующий класс сообщений:

public class MyMessage {

   public MyMessage(String receiver) {
      this.receiver = receiver;
   }

   private String receiver;

   public void send() {
      //some implementation for sending the mssage to the receiver
   }
}

Если определить интерфейс для этого класса, чтобы я мог иметь больше классов, реализующих интерфейс сообщений, я могу определить только метод send, а не конструктор. Итак, как я могу гарантировать, что каждая реализация этого класса действительно имеет набор приемников? Если я использую метод типа setReceiver(String receiver), я не могу быть уверен, что этот метод действительно вызван. В конструкторе я мог бы это гарантировать.

Ответ 1

Взяв некоторые из описанных вами вещей:

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

"Если определить интерфейс для этого класса, чтобы я мог иметь больше классы, которые реализуют интерфейс сообщений, я могу определить только send, а не конструктор"

... эти требования в точности соответствуют абстрактным классам.

Ответ 2

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

Или в коде:

interface Named { Named(String name); }
interface HasList { HasList(List list); }

class A implements Named, HasList {

  /** implements Named constructor.
   * This constructor should not be used from outside, 
   * because List parameter is missing
   */
  public A(String name)  { 
    ...
  }

  /** implements HasList constructor.
   * This constructor should not be used from outside, 
   * because String parameter is missing
   */
  public A(List list) {
    ...
  }

  /** This is the constructor that we would actually 
   * need to satisfy both interfaces at the same time
   */ 
  public A(String name, List list) {
    this(name);
    // the next line is illegal; you can only call one other super constructor
    this(list); 
  }
}

Ответ 3

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

Используемый пример использования сродни абстрактному классу, в котором конструктор вызывает метод абстрактного метода, который реализуется в дочернем классе.

Врожденная проблема заключается в том, что при выполнении базового конструктора дочерний объект еще не сконструирован, а в непредсказуемом состоянии.

Подводя итог: запрашивается ли проблема при вызове перегруженных методов из родительских конструкторов, чтобы процитировать mindprod:

В общем, вы должны избегать вызова каких-либо не конечные методы в конструкторе. Проблема в том, что экземпляр инициализаторы/переменная инициализация в производном классе выполняется после конструктор базы класс.

Ответ 4

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

Вторая причина - во время создания объекта подкласс вызывается родительский конструктор. Но если будет реализовано более одного интерфейса, тогда конфликт во время вызова конструктора интерфейса будет происходить, когда конструктор интерфейса вызовет первый

Ответ 5

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

Ответ 6

Смотрите этот вопрос, почему (взято из комментариев).

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

Ответ 7

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

Ответ 8

Вот пример использования этого Technic. В этом конкретном примере код делает вызов Firebase, используя mock MyCompletionListener, который является интерфейсом, маскированным как абстрактный класс, интерфейс с конструктором

private interface Listener {
    void onComplete(databaseError, databaseReference);
}

public abstract class MyCompletionListener implements Listener{
    String id;
    String name;
    public MyCompletionListener(String id, String name) {
        this.id = id;
        this.name = name;
    }
}

private void removeUserPresenceOnCurrentItem() {
    mFirebase.removeValue(child("some_key"), new MyCompletionListener(UUID.randomUUID().toString(), "removeUserPresenceOnCurrentItem") {
        @Override
        public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {

        }
    });
    }
}

@Override
public void removeValue(DatabaseReference ref, final MyCompletionListener var1) {
    CompletionListener cListener = new CompletionListener() {
                @Override
                public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
                    if (var1 != null){
                        System.out.println("Im back and my id is: " var1.is + " and my name is: " var1.name);
                        var1.onComplete(databaseError, databaseReference);
                    }
                }
            };
    ref.removeValue(cListener);
}

Ответ 9

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

interface IMyMessage(){
    @NonNull String getReceiver();
}
  • он не сломает инкапсуляцию
  • он позволит всем, кто использует ваш интерфейс, знать, что объект Receiver должен быть передан классу каким-либо образом (либо конструктором, либо установщиком)