Зачем нужны интерфейсы в ООП?
На русском Stackoverflow спросили зачем в Java нужны интерфейсы? Народ дал много интересных ответов, но все они так или иначе говорили о том ЧТО есть интерфейс и КАК устроена его реализация. О практической пользе никто не сказал. Т.е. ответ на вопрос для чего используются интерфейсы дан не был. Видимо потому, что для большинства это и так ЯСНО. Но, думаю, есть те, которые понимаю ЧТО и КАК, но не знают ДЛЯ ЧЕГО.
Я дал такой ответ:
–
Допустим, мы создали Framework, который определяет, совершил ли пользователь double-click по экрану.
Там мы определили функцию: что_делать_если_пользователь_кликнул_2_раза_по_экрану().
Но мы решаем не определять поведение этой функции сами, а предоставить эту реализацию программисту, использующему наш фреймворк. Предоставление этой реализации можно сделать через механизм интерфейсов.
Функцию: что_делать_если_пользователь_кликнул_2_раза_по_экрану() засовываем в интерфейс.
И, таким образом, сам момент двойного клика по экрану определяет наш фреймворк, а вот что делать (рисовать звездочки на экране, запустить проигрывание музыки и т.д.) после этого события решает программист, который реализует наш интерфейс.
Польза: программисту не надо думать, как словить double-click. За ним только реализация ответа на это событие.
–
Конечно, это только одна сторона пользы от интерфейсов. Зато очень наглядная на мой взгляд. Другая, очевидная поьза от интерфейсов - это придание гибкости коду в проекте (особенно в больших). См. e.g. принципы SOLID: academy.realm.io/posts/donn-felker-solid-part-5/
Для себя так понял практическую пользу интерфейсов. Как-то разбирал одну библиотеку, которая реализовывала Swipe&Dismiss карточек в RecyclerView. Эта библиотека реализовывала свой колбэк тоучхелпера:
И соответственно в адаптере RecyclerView, нужно было реализовать функцию, которая вызывалась после Swipe&Dismiss в ItemTouchHelperCallBack. Соответственно передать реализацию этой функции в адаптер можно было только через механизм интерфейсов.
Еще раз наш колбэк тоучхелпера уже с интерфейсом и функцией, которая использует реализацию интерфейса:
Простыми словами, функция которая реализует Swipe как бы говорит: “Чтобы я работала, мне нужен объект, который реализует интерфейс OnSwipListener. И не важно какой именно, я не должна знать это заранее. Просто объект, который реализует интерфейс”. Таким образом, мы избавляемся от зависимости между различными модулями программы.
Вот схема адаптера:
Таким образом, мы видим чем может быть полезен интерфейс. Скажем так, отложеной реализацией, когда мы все подготавливаем для какого-то действия, а потом, пользуясь этой подготовкой, реализуем только само действие.
Кстати, вот как реализация интерфейса связывается с расширяющим классом (в классе, где мы готовили наш RecyclerView и привязывали к нему адаптер):
С помощью instanseof мы проверяем, есть ли реализация нашего интерфейса в адаптере. Получаем эту реализацию - swipListener. И привязываем ее - setOnSwipListener(swipListener).
Так то.