fog
18 уровень

Что такое интерфейсы

Статья из группы Random
Интерфейс - это публичный общепринятый контракт (соглашение), описывающий некоторое поведение. Для чего они нужны? Например, пусть у нас есть ссылка указывающая на список строк. Предположим этот в этот список в начале добавляется множество элементов, а затем, весь список обрабатывается один раз. Допустим мы решили последовать известной рекомендации и использовать класс ArrayList:
ArrayList<String> list = new ArrayList<>();
Мы написали поведение программы в 100500 строк кода, где использовался этот список строк, и для оптимизации работы использовали методы специфичные для класса ArrayList. Например ensureCapacity(). Пока строки добавляются в конец списка, у нас всё прекрасно и быстро работает. Но вот у нас возникла потребность переориентировать нашу программу на немного другой вид работ, где строки добавляются преимущественно в начало списка. Для такого характера нагрузки гораздо больше подходит LinkedList. Но если мы захотим перевести свою программу из 100500 строк кода на рельсы LinkedList, то нам понадобится отыскать и убрать использование специфичных для ArrayList методов, возможно местами сильно меняя логику отдельных участков программы. Если бы мы использовали только те методы, которые имеются и в ArrayList, и в LinkedList, то нам бы этого делать не пришлось. Мы бы могли всего лишь изменить одну строчку кода - объявление списка:
LinkedList<String> list = new LinkedList<>();
Мы можем заметить, что было бы удобней вынести объявление методов общих, для этих классов, в класс-предок, возможно абстрактный, например AbstractList. В этом случае мы могли бы объявить наш список так:
AbstractList<String> list = new ArrayList<>();
И смогли бы быстро переключить реализацию вот так:
AbstractList<String> list = new LinkedList<>();
Но в этом случае, классы, которые мы можем использовать в нашей программе, ограничены только потомками класса AbstractList, даже если если есть более подходящие под задачу классы, не являющиеся потомками AbstractList, но имеющие те же методы с тем же поведением. Как быть? Именно поэтому были изобретены интерфейсы. Интерфейс - это такое соглашение о наборе методов и их поведении, которое могут обязаться соблюдать совершенно не связанные классы, позволяя ссылаться на любой из них с помощью единой ссылки. Например так:
List<String> list;
list = new ArrayList<>();
list = new LinkedList<>();
list = new AnotherListClass<>();
Даже если AnotherListClass не имеет с классами ArrayList и LinkedList общих классов-предков, кроме Object. Хорошим примером интерфейса, является рулевое управление автомобиля - у автомобиля есть руль, педали и коробка передач. У абсолютного большинства автомобилей, эти элементы следуют одному соглашению о поведении. Например, если повернуть рулевое колесо против часовой стрелки, автомобиль совершит поворот влево, а не увеличит скорость, независимо от своей марки. Если вы умеете использовать эти элементы управления, вы без особых усилий сможете справиться с любым автомобилем, независимо от его модели, года выпуска, марки и типа двигателя. Более того, можно представить ситуацию, в которой совершенно другой вид транспорта (к примеру, космический корабль) имеет тот же интерфейс управления, что и автомобили. Если вы, умея водить автомобиль, попадёте в кресло пилота такого корабля, то сможете не потеряться и в этой ситуации. Ещё раз повторим:
  • Интерфейс это контракт (соглашение) о поведении.
  • Множество классов, даже не связанных отношением наследования, могут объявить, что они обязуются соблюдать этот контракт (имплементация интерфейса).
  • Вынесение описания поведения в отдельный интерфейс очень удобно, так как увеличивает гибкость кода, позволяя переключать реализацию (класс имплементирующий интерфейс) интерфейса, на классы не связанные отношением наследования.
Комментарии (9)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
ШкольниК Уровень 19, Бузулук, Россия
16 августа 2021
аОаОа!_=_!
fFamous Уровень 51, Санкт-Петербург
16 августа 2021
Спасибо за развернутый ответ, теперь пришло еще больше понимания. Получается, что при создании нового объекта какого-то типа, следует использовать интерфейс или класс предок в качестве типа переменной, если есть. А есть обратные случаи, когда этого делать не стоит? Спасибо!