Рубрики
Без рубрики

Вступающий в силу Java Вторник! Предпочитайте интерфейсы абстрактным классам

Погружение в главу 20 Эффективной Java. Помеченный java, эффективный, наследование, архитектура.

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

Что такого хорошего в интерфейсах:

  • Интерфейсы могут быть добавлены постфактум.
    • В то время как иерархия классов является довольно тяжелой и жесткой вещью, которую можно изменить после факта, интерфейс может быть довольно простым в добавлении и не изменяет семантику существующего класса.
  • Интерфейсы допускают смешанное поведение.
    • Добавление – это дополнительное поведение в дополнение к основной цели класса. Например, Сопоставимый является примером смешивания. Хотя он определяет, что объект обладает определенным поведением, он не отнимает у корневого типа объекта.
  • Интерфейсы позволяют совместно использовать поведение, не полагаясь на иерархии
    • Классы заставляют нас использовать расширение для добавления в поведение. Это требует, чтобы мы построили иерархию, позволяющую это сделать. Хотя организация наших занятий по иерархии может быть уместной и полезной, во многих случаях это не самый эффективный способ выразить это.

Эффективная Java затем переходит в интересный шаблон, в котором мы можем получить лучшие результаты как интерфейсов, так и абстрактных классов. Идея состоит в том, чтобы продвинуть все части реализации как можно ниже по иерархии реализации, в то же время предоставляя пользователям помощников по коду, чтобы помочь им на их пути. Есть много вещей, которые вы можете поместить непосредственно в интерфейс, таких как сигнатуры методов и методы по умолчанию. Однако есть кое-что, что мы не сможем предоставить в нашем интерфейсе. Например, переменные-члены или непубличные статические члены. Так что же нам делать в таких ситуациях? Мы только что рассмотрели, как мы должны отдавать предпочтение интерфейсам, но мы можем чувствовать, особенно если интерфейс довольно сложный или сложный (подумайте об интерфейсе List ), что мы должны предоставить начальное местоположение для разработчиков, с которых можно начать, или что есть общие функции, которые понадобятся или понадобятся каждой реализации, которые не вписываются в разрешенные элементы интерфейса.

Вот где скелетные реализации являются полезной конструкцией./|скелетная реализация дает нам лучшее из обоих миров. На практике это просто абстрактный класс, который реализует интерфейс, а затем реализует не примитивные методы интерфейса. Делая это, мы можем взять на себя большую часть работы по реализации интерфейса. Вы часто можете распознать эти скелетные реализации в дикой природе, потому что они часто следуют одному и тому же соглашению об именовании, Аннотация <Интерфейс> где <Интерфейс> - это имя интерфейса, для которого класс предоставляет скелетный интерфейс. Например, Коллекция рефератов , Набор рефератов и т.д. Когда этот шаблон выполнен правильно, он может сделать реализацию интерфейса тривиальной. Например, давайте посмотрим, как реализовать Список с помощью Абстрактного списка скелетная реализация .

static List intArrayAsList(int[] array) {
  return new AbstractList {
    @Override
    public Integer get(int i) {
      return array[i];
    }

    @Override
    public Integer set(int i) {
      int oldValue = array[i];
      array[i] = i;
      return oldValue;
    }

    @Override
    public int size() {
      return array.length;
    }
  };
}

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

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

Оригинал: “https://dev.to/kylec32/effective-java-tuesday-prefer-interfaces-to-abstract-classes-21cn”