Подтвердить что ты не робот

Интерфейсы в Java 8

J. Блох в своей Эффективной Java, написанный для Java 6, упомянул следующее (Пункт 17):

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

Пункт 18:

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

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

Теперь в Java 8 с его реализацией по умолчанию (с использованием других методов в интерфейсе) интерфейсы опасны для наследования.

Например:

public inteface MyInterface{

   public void compute(Object o);

   public default void computeAll(List<Object> oo){
         for(Object o: oo)
            compute(o);       //self-use
   }
}

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

  • Переопределение методов, подобных этому (похоже на то, что предоставил J.Bloch):

    public class MyInterfaceCounter implements MyInterface{
    
      private int count = 0;
    
      @Override
      public void compute(Object o) {
        count++;
      }
    
      @Override
      public void computeAll(List<Object> oo){
        count += oo.size();            //Damn!!
        MyInterface.super.computeAll(oo);
      }
    }
    
  • Клиент получает доступ к внутренним интерфейсам, т.е. должен знать о реализации по умолчанию.

Что с ним делать в Java 8? Применяются ли правила от Эффективной Java?

Кроме того, мы не можем объявить метод по умолчанию как final (как это можно сделать для классов, это сделало бы самоиспользование не слишком опасным для переопределений).

4b9b3361

Ответ 1

Хорошо, ответьте на ваш предыдущий вопрос и посмотрите, что мы можем здесь применить:

Вы можете просто избежать самопомощи.

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

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

Это также не работает в интерфейсе.

Вы можете сделать класс окончательным, поэтому его нельзя продлить.

Это не будет работать в интерфейсе.

Вы можете описать шаблоны самообслуживания класса в своем комментарии Javadoc (отвечающем требованию дать другим знать).

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