Интерфейс - это публичный общепринятый контракт (соглашение), описывающий некоторое поведение.
Для чего они нужны?
Например, пусть у нас есть ссылка указывающая на список строк. Предположим этот в этот список в начале добавляется множество элементов, а затем, весь список обрабатывается один раз.
Допустим мы решили последовать известной рекомендации и использовать класс
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
.
Хорошим примером интерфейса, является рулевое управление автомобиля - у автомобиля есть руль, педали и коробка передач. У абсолютного большинства автомобилей, эти элементы следуют одному соглашению о поведении. Например, если повернуть рулевое колесо против часовой стрелки, автомобиль совершит поворот влево, а не увеличит скорость, независимо от своей марки.
Если вы умеете использовать эти элементы управления, вы без особых усилий сможете справиться с любым автомобилем, независимо от его модели, года выпуска, марки и типа двигателя. Более того, можно представить ситуацию, в которой совершенно другой вид транспорта (к примеру, космический корабль) имеет тот же интерфейс управления, что и автомобили. Если вы, умея водить автомобиль, попадёте в кресло пилота такого корабля, то сможете не потеряться и в этой ситуации.
Ещё раз повторим:
- Интерфейс это контракт (соглашение) о поведении.
- Множество классов, даже не связанных отношением наследования, могут объявить, что они обязуются соблюдать этот контракт (имплементация интерфейса).
- Вынесение описания поведения в отдельный интерфейс очень удобно, так как увеличивает гибкость кода, позволяя переключать реализацию (класс имплементирующий интерфейс) интерфейса, на классы не связанные отношением наследования.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ