В чем суть интерфейсов в программировании?
Не совсем ясно, для чего именно предназначены интерфейсы. Зачем мне в одном месте описывать методы, а в другом реализовывать? Зачем именно нужно дополнительное место для описания, если я могу это сделать сразу в классе? Или же это сделано для удобства восприятия кода? Например, если вижу, что класс наследуется от интерфейса, то знаю, каким функционалом он обладает? Если да, то почему бы не придумать имя класса, из которого будет ясна функциональность? Что первично — интерфейс, или класс? По возможности, приведите примеры кода(желательно не из объектной области, желательно на Java), где будет показано, что в данной ситуации необходимо использовать интерфейс, или что его использование удобнее, чем не использование. В книгах везде приводят примеры того, что может делать интерфейс, но в примерах из книги я не вижу крайней необходимости его использования. Спасибо!
- Вопрос задан более трёх лет назад
- 53884 просмотра
Комментировать
Решения вопроса 1
Я делаю систему контроля яркости.
Я хочу настраивать яркость всего (гирлянды, люстры, фонарика, экрана телефона).
В коде выглядит примерно так
class BrightControl public void setDefaultBright(Object obj) < obj.setBright(10); >>
Метод setDefaultBright принимает любой объект. Ведь мне всё равно яркость чего настраивать.
Мой код используют другие разработчики, я не могу контролировать их.
Как мне убедиться, что у объекта, который мне пришел в качестве аргумента, есть метод setBright?
Я пишу интерфейс, и говорю, что метод setDefaultBright принимает только объекты, которые реализуют этот интерфейс.
Если кроме меня самого никто не будет использовать эту систему контроля яркости. То я просто буду держать у себя в голове, что в метод setDefaultBright можно отправлять только объекты, у которых есть метод setBright, но поддержка кода усложняется, через год и не вспомнишь.
Ответ написан более трёх лет назад
Нравится 33 3 комментария
Спасибо за нормальное объяснение) целый день разбирался)
Спасибо за нормальное пояснение!
Правильно я понимаю что в случае использования утиной типизации (как в Ruby) необходимость использывать интерфейсы отпадает? Или у них есть ещё какое-то прикладное применение?
Александр Краснов @Pompeius_Magnus
Rozello, необходимость остается, но ЯП не будет вас ограничивать этим. Интерфейсы — это прием проектирования, а не особенность конкретного инструмента
Ответы на вопрос 8

Linux system administrator
Интерфейс это фактически регламент взаимодействия.
Класс который реализует интерфейс обязан реализовывать все его методы.
В интерфейсе вы описываете лишь сигнатуры методов, то есть вы указываете что класс наследник должен уметь делать, но как он будет это делать, тот решает сам.
Таким образом вы уверенны, что если класс реализует тот или иной интерфейс, все объекты данного класса имеют определенный набор методов.
ООП — мир абстракций 🙂 Впустите его в себя 🙂 Интерфейсы это еше одна абстракция позволяющая отделить описание от реалзиации.
«Придумать класс с правильным именем» — так вы не сможете заставить «наследников» реализовывать функционал.
Интерфейсы располагаются на уровень выше классов, если можно так выразиться. Они неявно «объединяют» классы схожие по каким то общим признаком, и которые обязаны (по логике вашего приложения) реализовывать те или иные методы.
interface Instruments < final static String key = "До мажор"; public void play(); >class Drum implements Instruments < public void play() < System.out.println("бум бац бац бум бац бац"); >> class Guitar implements Instruments < public void play() < System.out.println("до ми соль до ре до"); >>
p.s: программисты дополнят и поправят.
Ответ написан более трёх лет назад
Нравится 19 2 комментария
syntax @syntax Автор вопроса
«В интерфейсе вы описываете лишь сигнатуры методов, то есть вы указываете что класс наследник должен уметь делать, но как он будет это делать, тот решает сам.
Таким образом вы уверенны, что если класс реализует тот или иной интерфейс, все объекты данного класса имеют определенный набор методов.»
Почему я не могу сделать это прямо в классе? Зачем интерфейс? Я же и без него могу быть уверенным, что объекты будут обладать функционалам, описав методы в самом классе. Зачем мне кто то(интерфейс) должен говорить, какие мне методы реализовать? Если я знаю, что должен описать play(), то я могу это сделать прямо в классе, не используя интерфейс. И так могу сделать со всеми, кому нужен play(). Не понятно, в чём конкретно выгода?

Посмотрите на это с другой стороны.
Вы отдаете кому то решение и позволяете его «расширять». Но для того чтобы обеспечить совместимость на вашей стороне вы должны быть уверены, что все что будет сделано ниже с использованием того интерфейса который Вы дали, будет иметь набор методов (все объекты).
Если вы их опишите в классе и отнаследуете — то может случиться так что для данного объекта даная конкретная реализация метода не подходит. Вы не можете никак регламентировать то что должен делать метод. Интерфейс как раз и нужен для этого регламента.
Я же говорю интерфейсы нужны не для тех кто «снизу», а для тех кто «сверху».
Это договор с одной стороны вам дают функционал и интерфейс, со своей стороны вы обязуетесь реализовать интерфейс для использования этого функционала.
Косвеннным плюсом во всем этом является предсказуемость поведения объекта. Зная какой интерфейс он реализует, вы уже знаете что то о его поведении.

rEAcT1oNmanT1s @rEAcT1oNmanT1s
Да, это сделано именно для восприятия человеком кода. Легкие программы, где не особо много строк кода, не сильно сложны для восприятия человека, а программы которые имеют тысячи строк кода, уже соответственно нужно разделять на файлы в одних файлах лежат условия «что нужно сделать?», а в других «как это сделать?».
Существует еще принцип модульности который говорит, что программа может быть разделена на модули или блоки. В блоке содержится заголовочный файлы и исполняющий файл о которых я говорил раньше.
Если программа огромная и вы об это знаете заранее, то её стоит разбить заранее на модули. Зачем или почему? Первая причина это воспринимаемость кода человеком, о котором уже шла речь, а второе будет намного легче найти ошибки в исходном коде, который вы будете писать и они будут.
P.S. Даже когда пишите что-то или задаете вопросы, можете разделять на блоки текста, как написал я, так воспринимается легче чем то, что написано в куче , не правда ли?
Ответ написан более трёх лет назад
Комментировать
Нравится 4 Комментировать

Без интерфейса (как концепции) немыслимы три из четырех основных понятий ООП.
Конкретно в Java интерфейсы как отдельные сущности нужны, потому что нет множественного наследования. В C++ и многих других языках с поддержкой множественного наследования интерфейсов как отдельной сущности нет (чисто виртуальный класс — частный случай обычного абстрактного класса).
Ответ написан более трёх лет назад
Комментировать
Нравится 3 Комментировать
Для начала нужно сразу понять, что интерфейс это частный случай класса. Но в Java оно имеет отдельное ключевое слово, а в C++ это просто класс без реализации. Поэтому интерфейс просто задает некий стандарт для работы с кучей разнообразных реализаций.
Например, интерфейс Iterable говорит, что классы реализующие данный интерфейс имеют элементы и их можно перебирать в цикле вызывая метод next(). А значит, если создаете какой-то контейнер или коллекцию, то можно реализовать Iterable. Не выдумывая свои методы для работы с контейнером. Тем самым появляется некий общий стандарт — интерфейс для работы с контейнерами.
А если вы делаете игру, то можете создать интерфейс Unit, тем самым задав классам определенное поведение. Например, unit должен обязательно иметь метод atack(), isDead() и т.д.
А дальше, в цикле делаете проверку всех юнитов:
loop(. ) if (unit.isDead())
removeFromMap(unit);
>
Ну и конечно Unit может быть и просто классом или абстрактным классом, в котором реализованы atack и isDead, а может быть только isDead, потому что attack у каждого типа юнита индивидуально и требует собственной реализации. Т.е. приходим к тому, что интерфейс это также частный случай абстрактного класса.
Т.е. тут уже вступает в действие полиформизм, т.е. интерфейсы по сути дают полиформизм. Ну, а в Java они еще позволяют делать множественное наследование или другими словами задать классу несколько свойств поведения, например Unit может быть также и Iterable, тем самым можно дать юнитам инвентарь и перебирать элементы в нем.
И соответсвенно если Unit у вас будет классом или абстрактным классом, то унаследовав Unit в Java, вы просто не сможете дать наследнику еще и Iterable поведение, если Iterable будет тоже классом.
OrcWarrior implements Unit, Iterable — так можно
OrcWarrior extends Unit, Iterable — так в Java нельзя, но можно в С++, а Unit и Iterable тогда всегда будут объявляться как class.
Из-за этого, в Java приветствуется не наследование, а композиция. Т.е. нафига каждый раз реализовывать Unit.isDead, если он стандартный? Поэтому, создается скажем класс UnitAI и делается следующее:
class OrcWarrior implements Unit, Iterable UnitAI ai;
interface Unit void attack();
UnitAI getAI();
>
Вот это называется композиция, т.е. в OrcWarrior, HumanWarrior вы подмешиваете UnitAI, в котором уже реализовано isDead, и тем самым не нужно каждый раз его реализовывать одним и тем же кодом. В С++ такого можно не делать, там есть поддержка множественного наследование, но оно имеет свои минусы. Впрочем, как и композиция имеет плюсы/минусы.
Интерфейс
Интерфейс — это набор инструментов, который позволяет пользователю взаимодействовать с программой. В более широком смысле термин обозначает любые инструменты для соприкосновения между разными системами и сущностями. Часто говорят о графическом интерфейсе — простыми словами, это внешний вид сайта, программы или приложения.

«IT-специалист с нуля» наш лучший курс для старта в IT
Слово буквально означает «место соприкосновения», поэтому в IT интерфейсом могут называть разные сущности, с первого взгляда не похожие друг на друга. Например, в объектно-ориентированном программировании интерфейс — это набор методов сущности, то есть набор действий, с помощью которых она может взаимодействовать с другими. В веб-разработке интерфейс — внешний вид сайта. А для консольной программы интерфейс — набор команд, которые можно вводить в консоль, чтобы управлять поведением этой программы.
Все эти значения объединяет одно: то, что называется интерфейсом, служит для связи между одним и другим.
Профессия / 8 месяцев
IT-специалист с нуля
Попробуйте 9 профессий за 2 месяца и выберите подходящую вам

Кто работает с интерфейсами
Интерфейсами пользуются абсолютно все, кто использует компьютеры, смартфоны или другие гаджеты. Интерфейс есть практически у любой программы, с которой вы работаете: браузера, графического редактора, мессенджера и чего угодно другого. С программой без интерфейса нельзя взаимодействовать. Это службы операционной системы, системные процессы, которые работают «в фоне» без участия пользователя.
В более узком смысле с интерфейсами работают UI-дизайнеры или разработчики, если речь идет не о графическом интерфейсе. Разработчики же реализуют интерфейс так, чтобы он был функциональным и понятным.
Какими бывают типы интерфейсов
GUI
Графический интерфейс, Graphic User Unterface — то, о чем мы говорили выше. Вы открываете любую программу, и на экране появляется окно. Все, что в этом окне, — текст, кнопки, слайдеры, картинки — интерфейс программы. То же самое с сайтами и приложениями. Внешний вид открывшегося сайта — его графический интерфейс. Окно с приложением — интерфейс.
CLI
Это аббревиатура для интерфейса командной строки, Command Line Interface. Он текстовый, не графический. Все, что происходит, описывается текстом; команды пользователь набирает в отдельной строке, самой нижней. Этот интерфейс выглядит просто как множество строк текста на однотонном фоне. Иногда текст разных цветов: цвета обозначают разные виды информации.
Когда-то графических интерфейсов не существовало, и люди работали за компьютером через CLI. И сейчас есть программы или даже целые операционные системы без GUI. Все взаимодействие с ними происходит через командную строку.
«Базовый» CLI системы включает в себя набор команд, которые нужны для управления ОС. Когда вы скачиваете какой-то инструмент или программу, чаще всего профессиональные, вы иногда можете установить вместе с ней ее CLI, чтобы более гибко управлять процессами.
Интерфейсом командной строки пользуются в основном специалисты: разработчики, системные администраторы, сетевые инженеры и другие.
API
Application Programming Interface — отдельный вид интерфейса. Им пользуются не люди, а программы, поэтому он и называется программным. Например, если владелец сайта добавляет на страницы возможность комментирования через соцсети — он пользуется API соцсети, чтобы его сайт мог с ней связаться.
Жестовый и голосовой интерфейсы
С некоторыми устройствами можно взаимодействовать с помощью голоса и жестов. Пример — умный дом, который включает свет по определенному жесту, или колонка с голосовым помощником. Голос и жесты в таком случае — способ взаимодействия, то есть интерфейс.
Общение между двумя людьми — тоже пример голосового и жестового интерфейсов.
Узнать, как продумывать и разрабатывать хорошие, функциональные интерфейсы, вы можете на наших профессиональных курсах.
IT-специалист с нуля
Наш лучший курс для старта в IT. За 2 месяца вы пробуете себя в девяти разных профессиях: мобильной и веб-разработке, тестировании, аналитике и даже Data Science — выберите подходящую и сразу освойте ее.
Что такое интерфейс? Объясняем простыми словами

Пишем про дизайн и искусство. Всё, что вы хотели знать о настоящем, прошлом и будущем визуальной культуры.
Интерфейс — это термин, который встречается и в дизайне, и в айти. Он означает одно и то же? Или в каждой области подразумевается своё значение?
Простыми словами объясняют, что такое интерфейс, эксперт в UX/UI Евгений Князев и эксперт в web-разработке Михаил Малышев.

Евгений Князев
CEO Antro, арт-директор, продуктовый дизайнер. Спикер Product Sense, спикер ECOM Expo. Автор курса «Логомашины» по мобильным интерфейсам, член жюри Russian Drupal Awards.
Евгений Князев об интерфейсе на дизайнерском и глобальном
Что такое интерфейс
В самом слове «интерфейс» для человека, который немного знает английский, уже есть подсказки. Явно видно, что это про interaction ― взаимодействие ― и про face ― лицо. Правда, если подглядеть в какую-нибудь «Википедию» и прочитать там определения, то можно ничего не понять.
Всё достаточно просто: интерфейс — это какая-то штука, которая помогает взаимодействовать двум системам или, условно говоря, двум другим штукам.
Например, захотелось тебе попить кока-колки из кока-кольной реки. Скорее всего, ты попробуешь повзаимодействовать с ней при помощи рук. Руки — это интерфейс, через который твоя система взаимодействует с миром. Точнее, твой мозг: он что-то хочет сделать, но у него нет возможности влиять на предметы , поэтому он начинает использовать другие инструменты — например, твоё тело, которое тоже — интерфейс, а руки — его часть.
Интерфейс — это система интерфейсов
В принципе, ты можешь с помощью рук налить себе в ладошки кока-колку и вылакать её. Но это — пример плохого варианта интерфейса: она будет проливаться, руки будут липкие и мокрые, что неприятно и, в общем-то, бестолково.
Есть кружка. Это тоже интерфейс — взаимодействия рук с кока-колкой и другими напитками. И вот получается уже система, которую можно декомпозировать :
- Мозг хочет напиток.
- Он для этого использует руки. Но только руки для колы — так себе интерфейс, поэтому…
- Он придумывает, как сделать с помощью рук какую-то штуку в зависимости от контекста и среды, в которой он находится. Например, делает кружку из каких-нибудь листьев и веток или покупает керамическую в магазине.
- И вот руки берут кружку — получается уже достаточно хороший интерфейс: кока-колка не проливается, мозг получает удовольствие от сахара.
Разным контекстам разные интерфейсы
Кружка может быть с ручкой, без ручки, состоять из стакана с подстаканником, который этому гладкому стакану добавляет ручку.
В зависимости от напитка кружка может меняться. Кока-колу можно пить из любой, даже из чашечки для эспрессо — может, это немного странно, но никто не осудит, а её вкус не особенно изменится.
Если ты будешь из кружки для эспрессо пить вино, то любители вина посмотрят косо — у них абсолютно другие требования к интерфейсу. Ёмкость для напитка, помимо утилитарной подачи напитка из среды в ЖКТ, должна соответствовать эстетическим требованиям и, например, позволять вину «раскрыться».

Какими интерфейсами занимаются дизайнеры
На языке продуктовых дизайнеров интерфейс — это, в первую очередь, видимая часть системы web-сервиса или мобильного приложения (браузера, игры, онлайн-магазина), с которой взаимодействует пользователь. Его задача — передавать информацию от юзера.


С дизайнерской точки зрения разница между веб- и мобильным интерфейсом есть, но в конечном счёте это всегда некоторый макет в Figma.

Работа дизайнера над интерфейсом отличается от создания графического или motion-дизайна. В продуктовом дизайне главное — не цепляющая эстетика форм, цветов, шрифтов и композиции. Визуальные образы (или UI) важны, они влияют на восприятие пользователем, но проектирование интерфейса не сводится к ним.
Заметка: с разделением UI и UX ситуация непроста. Во-первых, среди дизайнеров нет консенсуса на этот счёт. Во-вторых, у нас внутри компании он есть: UI — часть UX, так как user interface (UI) является частью пользовательского опыта (UX) и отделять один от другого, на наш взгляд, некорректно.
Слово design с английского переводится как «проектирование». Так что дизайн интерфейсов — это в первую очередь проектирование удобного приспособления, а не рисование и раскрашивание.
Проектировщику интерфейсов надо заботиться не только о том, чтобы его работа была красивой, но и как этим будут пользоваться — то есть о UX. Такой дизайнер должен смотреть шире, чем только на «лицо»: надо представлять и проектировать, как будет происходить взаимодействие. Поэтому в работе есть не только статичные картинки, но и анимации, проектирование переходов и откликов от системы.
И этот набор кнопок, текста, картинок, переходов и анимации позволяет и помогает человеку взаимодействовать с системой своего устройства, получая от неё нужный ему результат.
Сделать удачный интерфейс, а не лакать воду из ладошек, поможет знание 10 эвристик по Нильсену.

Михаил Малышев
Веб-разработчик, работал в «Рокетбанке» и «Яндексе». Frontend Tech Lead в Timestripe, Fullstack TypeScript Developer в Playdex. Ведёт телеграм-канал про фронтенд и веб 3.0.
Михаил Малышев об интерфейсе на айтишном
Что такое интерфейс в программировании
Простыми словами, интерфейс ― это соглашение, по которому компоненты компьютерной системы обмениваются информацией.
Обмен может происходить между программным обеспечением, компонентами компьютера, периферийными устройствами и другим железом, либо между человеком и компьютером.
Давайте рассмотрим несколько примеров интерфейсов, от самых высокоуровневых до низкоуровневых (речь идёт об уровнях абстракции: чем ниже уровень, тем глубже погружение в детали реализации и тем более подробно требуется описывать программу; например, zero-code-программирование находится на более высоком уровне по сравнению с обычным, потому что когда мы сами пишем код, то должны явно описывать каждую деталь).
Какие есть виды интерфейсов
Давайте рассмотрим три вида интерфейсов, с которыми взаимодействуют пользователи и разработчики.
Хардверные
Hardware-интерфейсы нужны для подключения физических устройств друг к другу.
— Подскажите, какой интерфейс у этой MIDI-клавиатуры?
— Она может работать и по MIDI, и по USB.
Сюда относятся как проводные интерфейсы вроде USB или Thunderbolt, так и беспроводные — WiFi и Bluetooth.
Программные
Эта аббревиатура расшифровывается как Application Programming Interface — интерфейс программирования приложения.
Эти интерфейсы используют для интеграции программ друг с другом. Например, чтобы получить данные с сервера, мобильное приложение обращается к API сервера.
API чётко регламентирован и может сильно отличаться от приложения к приложению. Поэтому разработчики API предоставляют документацию, где рассказывают для других разработчиков, как интегрироваться с этим API.
Апишка — так разработчики часто называют API.
Эндпоинт — один из доступных методов в API, например эндпоинт для добавления песни в плейлист в API Spotify.
Ручка — так эндпоинт называют в «Яндексе».
- В объектно-ориентированном программировании
Интерфейс в объектно-ориентированном программировании — это описание структуры объекта, без деталей реализации.


Пользовательские
Пользовательские интерфейсы предназначены для работы человека с программой.
Все интерактивные элементы на экране компьютера — части графического пользовательского интерфейса (GUI — Graphical User Interface).
Но не все пользовательские интерфейсы графические. Например, существует вид пользовательских интерфейсов, который называется CLI — Command Line Interface. Это консольный интерфейс для программы, для работы с которым нужно вводить команды в терминал. Программы, созданные для разработчиков, часто используют CLI вместо GUI, потому что его гораздо проще создать и развивать. Кроме того, CLI используют для автоматизации, потому что консольные команды можно выполнять внутри собственных программ. Таким образом, консольные интерфейсы одновременно являются и пользовательскими, и программными.
Больше интересного про дизайн в нашем телеграм-канале. Подписывайтесь!
Интерфейс (объектно-ориентированное программирование)
Интерфе́йс (от лат. inter — «между», и face — «поверхность») — семантическая и синтаксическая конструкция в коде программы, используемая для специфицирования услуг, предоставляемых классом или компонентом. Интерфейс определяет границу взаимодействия между классами или компонентами, специфицируя определенную абстракцию, которую осуществляет реализующая сторона. В отличие от многих других видов интерфейсов, интерфейс в ООП является строго формализованным элементом объектно-ориентированного языка и в качестве семантической конструкции широко используется кодом программы.
Описание и использование интерфейсов
Описание ООП-интерфейса, если отвлечься от деталей синтаксиса конкретных языков, состоит из двух частей: имени и методов интерфейса.
- Имя интерфейса строится по тем же правилам, что и другие идентификаторы используемого языка программирования. Разные языки и среды разработки имеют различные соглашения по оформлению кода, в соответствии с которыми имена интерфейсов могут формироваться по некоторым правилам, которые помогают отличать имя интерфейса от имён других элементов программы. Например, в технологии COM и во всех поддерживающих её языках действует соглашение, следуя которому, имя интерфейса строится по шаблону «I», то есть состоит из написанного с заглавной буквы осмысленного имени, которому предшествует прописная латинская буква I (IUnknown, IDispatch, IStringList и так далее).
- Методы интерфейса. В описании интерфейса определяются имена и сигнатуры входящих в него методов, то есть процедур или функций класса.
Использование интерфейсов возможно двумя способами:
- Класс может реализовывать интерфейс. Реализация интерфейса заключается в том, что в описании класса данный интерфейс указывается как реализуемый, а в коде класса обязательно определяются все методы, которые описаны в интерфейсе, в полном соответствии с сигнатурами из описания этого интерфейса. То есть, если класс реализует интерфейс, для любого экземпляра этого класса существуют и могут быть вызваны все описанные в интерфейсе методы. Один класс может реализовать несколько интерфейсов одновременно.
- Возможно объявление переменных и параметров методов как имеющих тип-интерфейс. В такую переменную или параметр может быть записан экземпляр любого класса, реализующего интерфейс. Если интерфейс объявлен как тип возвращаемого значения функции, это означает, что функция возвращает объект класса, реализующего данный интерфейс.
Как правило, в объектно-ориентированных языках программирования интерфейсы, как и классы, могут наследоваться друг от друга. В этом случае интерфейс-потомок включает все методы интерфейса-предка и, возможно, добавляет к ним свои собственные.
Таким образом, с одной стороны, интерфейс — это контракт, который обязуется выполнить класс, реализующий его, с другой стороны, интерфейс — это тип данных, потому что его описание достаточно четко определяет свойства объектов, чтобы наравне с классом типизировать переменные. Следует, однако, подчеркнуть, что интерфейс не является полноценным типом данных, так как он задаёт только внешнее поведение объектов. Внутреннюю структуру и реализацию заданного интерфейсом поведения обеспечивает класс, реализующий интерфейс; именно поэтому «экземпляров интерфейса» в чистом виде не бывает, и любая переменная типа «интерфейс» содержит экземпляры конкретных классов.
Использование интерфейсов — один из вариантов обеспечения полиморфизма в объектных языках и средах. Все классы, реализующие один и тот же интерфейс, с точки зрения определяемого им поведения, ведут себя внешне одинаково. Это позволяет писать обобщённые алгоритмы обработки данных, использующие в качестве типов параметры интерфейсов, и применять их к объектам различных типов, всякий раз получая требуемый результат.
Например, интерфейс « Cloneable » может описать абстракцию клонирования (создания точных копий) объектов, специфицировав метод « Clone », который должен выполнять копирование содержимого объекта в другой объект того же типа. Тогда, любой класс, объекты которого может понадобиться копировать, должен реализовать интерфейс Cloneable и предоставить метод Clone , а в любом месте программы, где требуется клонирование объектов, для этой цели у объекта вызывается метод Clone . Причем, использующему этот метод коду достаточно иметь только описание интерфейса, он может ничего не знать о фактическом классе, объекты которого копируются. Таким образом, интерфейсы позволяют разбить программную систему на модули без взаимной зависимости кода.
Интерфейсы и абстрактные классы
Можно заметить, что интерфейс, с точки зрения реализации, — это просто чистый абстрактный класс, то есть класс, в котором не определено ничего, кроме абстрактных методов. Если язык программирования поддерживает множественное наследование и абстрактные методы (как, например, C++), то необходимости во введении в синтаксис языка отдельного понятия «интерфейс» не возникает. Данные сущности описываются с помощью абстрактных классов и наследуются классами для реализации абстрактных методов.
Однако поддержка множественного наследования в полном объёме достаточно сложна и вызывает множество проблем, как на уровне реализации языка, так и на уровне архитектуры приложений. Введение понятия интерфейсов является компромиссом, позволяющим получить многие преимущества множественного наследования (в частности, возможность удобно определять логически связанные наборы методов в виде сущностей, подобных классам и допускающих наследование и реализацию), не реализуя его в полном объёме и не сталкиваясь, таким образом, с большинством связанных с ним трудностей.
Множественное наследование и реализация интерфейсов
Как правило, языки программирования разрешают наследовать интерфейс от нескольких интерфейсов-предков. Все методы, объявленные в интерфейсах-предках, становятся частью объявления интерфейса-потомка. В отличие от наследования классов, множественное наследование интерфейсов гораздо проще реализуется и не вызывает существенных затруднений.
Тем не менее, одна коллизия при множественном наследовании интерфейсов и при реализации нескольких интерфейсов одним классом всё-таки возможна. Она возникает, когда в двух или более интерфейсах, наследуемых новым интерфейсом или реализуемых классом, имеются методы с одинаковыми сигнатурами. Разработчики языков программирования вынуждены выбирать для таких случаев те или иные способы разрешения противоречий. Вариантов здесь несколько: запрет на реализацию, явное указание конкретного и реализация базового интерфейса или класса.
- Запрет. В одном классе просто запрещается реализовывать несколько интерфейсов, имеющих методы с одинаковыми сигнатурами. Если для какого-то класса требуется комбинация несовместимых интерфейсов, программист должен выбрать другой путь решения проблемы, например, выделить несколько классов, каждый из которых реализует один из необходимых интерфейсов, и использовать их экземпляры совместно.
- Явное разрешение неоднозначности. В случае обнаружения компилятором коллизии от программиста требуется явно указать, метод какого из интерфейсов он реализует и вызывает. То есть одноимённые методы реализуются раздельно, а при вызове указывается, какой из них вызывается. При вызове одноимённых методов через переменную типа интерфейс неоднозначность не возникает, если использованный в качестве типа переменной интерфейс имеет только один метод с заданным именем. Вариантом этого решения является явное переименование для совпадающих по именам наследуемых или реализуемых методов, за счёт чего в пределах реализующего класса нет одноимённых методов, но при обращении через интерфейс всегда вызывается нужная реализация.
- Общая реализация одноимённых методов. Если наследуется или реализуется несколько методов с одной и той же сигнатурой, то они объединяются в интерфейсе-наследнике, а в классе-реализаторе получают одну общую реализацию. Это хорошо подходит для случаев, когда одноимённые методы разных интерфейсов идентичны по предполагаемой функциональности, но может вызвать нежелательные эффекты, если поведение этих методов должно различаться.
Интерфейсы в конкретных языках и системах
Реализация интерфейсов во многом определяется исходными возможностями языка и целью, с которой интерфейсы введены в него. Очень показательны особенности использования интерфейсов в языках Java, Object Pascal системы Delphi и C++, поскольку они демонстрируют три принципиально разные ситуации: изначальная ориентация, применение для совместимости и эмуляция классами.
- В Java интерфейсы изначально входят в язык, являясь неотъемлемой его частью.
- В объектной подсистеме языка Object Pascal никаких интерфейсов не было, их поддержка была введена в Delphi 2 для обеспечения написания и использования COM-компонентов. Соответственно, механизм интерфейсов Delphi ориентирован, в первую очередь, на использование технологии COM.
- В C++ интерфейсов, строго говоря, нет вообще. Механизм, аналогичный интерфейсам (и исторически предшествующий им) реализуется другими средствами чрезвычайно мощной объектной подсистемы этого языка.
Delphi
В Delphi интерфейсы были введены для поддержки COM технологии фирмы Microsoft. Однако при выпуске Kylix интерфейсы как элемент языка были «отвязаны» от технологии COM. Все интерфейсы наследуются от интерфейса IInterface [1], который на платформе win32 совпадает с IUnknown , стандартным одноимённым COM-интерфейсом, подобно тому, как все классы в нём являются наследниками класса TObject . Явное использование в качестве предка IUnknown оставлено для кода, использующего технологию COM.
Пример объявления интерфейса:
IMyInterface = interface procedure DoSomething; end;
Для того, чтобы объявить о реализации интерфейсов, в описании класса необходимо указать их имена в скобках после ключевого слова class , после имени класса-предка. Так как интерфейс — это контракт, который нужно выполнить, программа не компилируется, пока в реализующем классе не будет реализована procedure DoSomething;
Вышеупомянутая ориентированность интерфейсов Delphi на технологию COM привела к некоторым неудобствам. Дело в том, что интерфейс IInterface (от которого наследуются все остальные интерфейсы) уже содержит три обязательных для COM-интерфейсов метода: QueryInterface,_AddRef, _Release , следовательно, любой класс, реализующий любой интерфейс, обязан реализовать эти методы, даже если по логике программы интерфейс и класс не имеют никакого отношения к COM. Необходимо заметить, что данные три метода также используются для контроля времени жизни объекта и реализации механизма запроса интерфейса через оператор «as».
Пример класса, реализующего интерфейс:
TMyClass = class(TMyParentClass, IMyInterface) procedure DoSomething; function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end; implementation
Программист должен правильно реализовать методы QueryInterface,_AddRef, _Release . Чтобы избавиться от необходимости писать стандартные методы, предусмотрен библиотечный класс TInterfacedObject — он реализует три вышеупомянутых метода и любой класс, наследуемый от него и его потомков, получает эту реализацию. Реализация этих методов в TInterfacedObject предполагает автоматический контроль за временем жизни объекта путем подсчета ссылок через методы _AddRef, _Release , которые вызываются автоматически при входе в область видимости и выходе из неё.
Пример класса — наследника TInterfacedObject :
TMyClass = class(TInterfacedObject, IMyInterface) procedure DoSomething; end;
При наследовании класса, реализующего интерфейс, от класса без интерфейсов, программист должен реализовать упомянутые методы вручную, определив наличие либо отсутствие контроля по подсчету ссылок, а также получение интерфейса в QueryInterface.
Пример произвольного класса без подсчета ссылок:
TMyClass = class(TObject, IInterface, IMyInterface) //IInterface function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; //IMyInterface procedure DoSomething; end; function TMyClass.QueryInterface(const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; function TMyClass._AddRef: Integer; begin Result := -1; end; function TMyClass._Release: Integer; begin Result := -1; end; procedure TMyClass.DoSomething; begin //Do something end;
C++
C++ поддерживает множественное наследование и абстрактные классы, поэтому, как уже упоминалось выше, отдельная синтаксическая конструкция для интерфейсов в этом языке не нужна. Интерфейсы определяются при помощи абстрактных классов, а реализация интерфейса производится путём наследования этих классов.
Пример определения интерфейса:
/** * interface.Openable.h * */ #ifndef INTERFACE_OPENABLE_HPP #define INTERFACE_OPENABLE_HPP // Класс интерфейса iOpenable. Определяет возможность открытия/закрытия чего либо. class iOpenable public: virtual ~iOpenable()> virtual void open()=0; virtual void close()=0; >; #endif
Интерфейс реализуется через наследование. Благодаря наличию множественного наследования, ничто не мешает реализовать в одном классе несколько интерфейсов, если в этом есть необходимость:
/** * class.Door.h * */ #include "interface.Openable.h" #include class Door: public iOpenable public: Door()std::cout <"Door object created":: endl;> virtual ~Door()> //Конкретизация методов интерфейса iOpenable для класса Door virtual void open()std::cout <"Door opened":: endl;> virtual void close()std::cout <"Door closed":: endl;> //Специфические для класса Door свойства и методы std::string mMaterial; std::string mColor; //. >;
/** * class.Book.h * */ #include "interface.Openable.h" #include class Book: public iOpenable public: Book()std::cout <"Book object created":: endl;> virtual ~Book()> //Конкретизация методов интерфейса iOpenable для класса Book virtual void open()std::cout <"Book opened":: endl;> virtual void close()std::cout <"Book closed":: endl;> //Специфические для класса Book свойства и методы std::string mTitle; std::string mAuthor; //. >;
Тестируем все вместе:
/** * test.Openable.cpp * */ #include "interface.Openable.h" #include "class.Door.hpp" #include "class.Book.hpp" //Функция открытия/закрытия любых разнородных объектов в которых реализован интерфейс iOpenable void openAndCloseSomething(iOpenable& smth) smth.open(); smth.close(); > int main() Door myDoor; Book myBook; openAndCloseSomething(myDoor); openAndCloseSomething(myBook); system ("pause"); return 0; >
Java
В отличие от C++, Java не позволяет наследовать больше одного класса. В качестве альтернативы множественному наследованию, существуют интерфейсы. Каждый класс в Java может реализовать любой набор интерфейсов. Порождать объекты от интерфейсов в Java нельзя.
Объявление интерфейсов
Объявление интерфейсов очень похоже на упрощенное объявление классов.
Оно начинается с заголовка. Сначала указываются модификаторы. Интерфейс может быть объявлен как public и тогда он будет доступен для общего использования, либо модификатор доступа может не указываться, в этом случае интерфейс доступен только для типов своего пакета. Модификатор abstract для интерфейса не требуется, поскольку все интерфейсы являются абстрактными классами. Его можно указать, но делать этого не рекомендуется, чтобы не загромождать код.
Далее записывается ключевое слово interface и имя интерфейса.
После этого может следовать ключевое слово extends и список интерфейсов, от которых будет наследоваться объявляемый интерфейс. Родительских типов (классов и/или интерфейсов) может быть много, главное, чтобы не было повторений, и чтобы отношение наследования не образовывало циклической зависимости.
Наследование интерфейсов действительно очень гибкое. Так, если есть два интерфейса, A и B , причем B наследуется от A , то новый интерфейс C может наследоваться от них обоих. Впрочем, понятно, что при наследовании от B , указание наследования от A является избыточным, так как все элементы этого интерфейса и так будут получены по наследству через интерфейс B.
Затем в фигурных скобках записывается тело интерфейса.
Пример объявления интерфейса:
public interface Drawable extends Colorable, Resizable >
Тело интерфейса состоит из объявления элементов, то есть полей-констант и абстрактных методов. Все поля интерфейса автоматически являются public final static , так что эти модификаторы указывать необязательно и даже нежелательно, чтобы не загромождать код. Поскольку поля являются финальными, необходимо их сразу инициализировать.
public interface Directions int RIGHT=1; int LEFT=2; int UP=3; int DOWN=4; >
Все методы интерфейса являются public abstract и эти модификаторы также необязательны.
public interface Moveable void moveRight(); void moveLeft(); void moveUp(); void moveDown(); >
Как мы видим, описание интерфейса гораздо проще, чем объявление класса.
Реализация интерфейса
Для реализации интерфейса он должен быть указан при декларации класса с помощью ключевого слова implements . Пример:
interface I void interfaceMethod(); > public class ImplementingInterface implements I void interfaceMethod() System.out.println("Этот метод реализован из интерфейса I"); > public static void main(String[] args) ImplementingInterface temp = new ImplementingInterface(); temp.interfaceMethod(); > >
Каждый класс может реализовывать любые доступные интерфейсы. При этом в классе должны быть реализованы все абстрактные методы, появившиеся при наследовании от интерфейсов или родительского класса, чтобы новый класс мог быть объявлен неабстрактным.
Если из разных источников наследуются методы с одинаковой сигнатурой, то достаточно один раз описать реализацию и она будет применяться для всех этих методов. Однако, если у них различное возвращаемое значение, то возникает конфликт. Пример:
interface A int getValue(); > interface B double getValue(); > interface C int getValue(); > public class Correct implements A, C // класс правильно наследует методы с одинаковой сигнатурой int getValue() return 5; > > class Wrong implements A, B // класс вызывает ошибку при компиляции int getValue() return 5; > double getValue() return 5.5; > >
C#
В C# интерфейсы могут наследовать один или несколько других интерфейсов. Членами интерфейсов могут быть методы, свойства, события и индексаторы:
interface I1 void Method1(); > interface I2 void Method2(); > interface I : I1, I2 void Method(); int Count get; > event EventHandler SomeEvent; string this[int index] get; set; > >
При реализации интерфейса класс должен реализовать как методы самого интерфейса, так и его базовых интерфейсов:
public class C : I public void Method() > public int Count get throw new NotImplementedException(); > > public event EventHandler SomeEvent; public string this[int index] get throw new NotImplementedException(); > set throw new NotImplementedException(); > > public void Method1() > public void Method2() > >
Интерфейсы в UML


Изображение интерфейса и реализующего его класса в UML.
Интерфейсы в UML используются для визуализации, специфицирования, конструирования и документирования стыковочных UML-узлов между составными частями системы. Типы и UML-роли обеспечивают механизм моделирования статического и динамического соответствия абстракции интерфейсу в конкретном контексте.
В UML интерфейсы изображаются как классы со стереотипом «interface». Либо в виде кружочков, в этом случае содержащиеся в интерфейсе UML-операции не отображаются.
См. также
- COM-интерфейс
- Компонентно-ориентированное программирование
- Интерфейс программирования приложений
- Абстрактный класс
Примечания
Ссылки
- Implement multiple interfaces
- Interface в javascript
- Найти и оформить в виде сносок ссылки на авторитетные источники, подтверждающие написанное.
- Проставив сноски, внести более точные указания на источники.
- Викифицировать статью.