что такое интерфейс ооп

Зачем нужны абстракции и интерфейсы

И что это вообще такое?

Как в старом анекдоте: про объектно-ориентированное программирование можно рассказать просто и неправильно либо сложно и неправильно. Мы попробуем рассказать про очередной аспект ООП просто.

Зачем это: ООП — одна из главных концепций современной разработки. Она применима не к каким-то конкретным языкам, это скорее способ мышления в программировании. Если вы понимаете ООП, ваш код на любом языке будет чище, читаемее и эффективнее.

В этой статье разберём два сложных понятия из объектно-ориентированного программирования: абстракции и интерфейсы. Это ещё одна ступень в понимании непостижимого.

Основные идеи из ООП

Абстракция

Представьте, что вы попросили нескольких человек описать в общих чертах, что такое телефон и как им пользоваться: пусть это будут бабушка, мама и подруга. Бабушка вспомнит про дисковые телефоны и трубки с витым проводом. Мама расскажет про радиотелефоны, у которых есть база и есть трубка, с которой можно ходить по всей квартире, а подруга начнёт описывать мобильник.

Несмотря на то что рассказы будут сильно отличаться между собой, у них будет несколько общих моментов про телефон:

Получается, что если представить абстрактный телефон, то получится такое устройство с динамиком, микрофоном и средством набора номера.

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

🔥 Абстракция — это когда мы сосредотачиваемся только на существенных для задачи деталях и игнорируем всё остальное. В ООП абстракция означает, что для каждого объекта мы задаём минимальное количество методов, полей и описаний, которые позволят нам решить задачу. Чем меньше характеристик, тем лучше абстракция, но ключевые характеристики убирать нельзя.

Чтобы работать с абстракциями, используют интерфейсы.

Интерфейс

Итак, у нас есть некое устройство с трубкой, микрофоном, динамиком и средством набора номера. Но если вы вспомните рассказы мамы, бабушки и подруги, то обнаружите вот что:

Всё это — интерфейсы. Они позволяют работать с объектом, не вникая в то, как он устроен внутри. Если вы умеете работать с интерфейсом номеронабирателя, то вам всё равно, нужно ли крутить диск, нажимать физические кнопки на радиотрубке или давить пальцем на сенсорный экран.

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

Интерфейсы — это действия над объектом, доступные другим объектам (поэтому они называются публичными).

Есть ещё инкапсулированные, то есть внутренние методы. Например, у микрофона есть публичный метод «Слушать голос», и есть внутренний метод «Преобразовать голос в электрические сигналы». С его помощью он взаимодействует с другими частями нашего абстрактного телефона. Про инкапсуляцию будет отдельный материал, потому что тема большая.

Сложная терминология

Строго говоря, интерфейсы — это не действия, а методы. Сейчас объясним.

В программировании есть операции — это простейшие действия, например, скопировать значение из одной переменной в другую.

Из простых действий составляются функции — это когда несколько операций «склеиваются» в нечто единое. Мы даём этой склейке название и получаем функцию. Например, может быть функция «проверить правильность электронного адреса», которая состоит из нескольких десятков простых операций.

На языке ООП функции, привязанные к объектам, называются методами. Просто такой термин. По сути это функции, то есть склеенные вместе операции.

Итого: метод — это набор простых действий, которые склеили в единое целое и засунули в объект.

Для чего это всё

Допустим, вы работаете в команде над большим продуктом. В таких случаях удобно разделить одну большую программу на множество мелких подпрограмм и сервисов, каждый из которых решает свою узкую задачу.

Если заранее не договориться о том, как эти компоненты обмениваются данными между собой, то может случиться то, о чём мы уже предупреждали:

Чтобы такого не было, поступают так:

Источник

ООП. Часть 6. Абстрактные классы и интерфейсы

Узнайте истинную мощь наследования и полиморфизма! Раскрываем секреты абстрактных классов и интерфейсов.

что такое интерфейс ооп. Смотреть фото что такое интерфейс ооп. Смотреть картинку что такое интерфейс ооп. Картинка про что такое интерфейс ооп. Фото что такое интерфейс ооп

что такое интерфейс ооп. Смотреть фото что такое интерфейс ооп. Смотреть картинку что такое интерфейс ооп. Картинка про что такое интерфейс ооп. Фото что такое интерфейс ооп

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

Все статьи про ООП

что такое интерфейс ооп. Смотреть фото что такое интерфейс ооп. Смотреть картинку что такое интерфейс ооп. Картинка про что такое интерфейс ооп. Фото что такое интерфейс ооп

Пишет о программировании, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.

Абстрактные классы

Особенность абстрактных классов в том, что их можно использовать только как родительский класс, то есть вы не можете создать объект. Для их объявления используется ключевое слово abstract.

Это может понадобиться, чтобы объединить реализацию других схожих классов. Например, в вашей игре должны быть персонаж игрока и NPC (неигровые персонажи). У них могут быть общие свойства (имя, координаты) и методы (перемещение, изменение анимации).

Чтобы не повторять код несколько раз, можно вынести реализацию этих свойств и методов в абстрактный класс Character:

Тут всё как у обычных классов, но в конце можно заметить объявление свойства и метода без реализации. Реализация этих абстрактных свойств должна находиться в дочернем классе:

Когда объявляется реализация такого члена класса, необходимо указать ключевое слово override. Абстрактными могут быть следующие члены класса:

Дочерний класс должен реализовывать все члены родительского абстрактного класса, кроме тех случаев, когда дочерний класс тоже абстрактный.

В остальном всё очень похоже на обычные классы. Например, поле Y класса Character публичное, чтобы можно было использовать его в свойстве Y дочерних классов.

что такое интерфейс ооп. Смотреть фото что такое интерфейс ооп. Смотреть картинку что такое интерфейс ооп. Картинка про что такое интерфейс ооп. Фото что такое интерфейс ооп

Абстрактный класс должен быть публичным.

Источник

что такое интерфейс ооп. Смотреть фото что такое интерфейс ооп. Смотреть картинку что такое интерфейс ооп. Картинка про что такое интерфейс ооп. Фото что такое интерфейс ооп NEWOBJ.ru → Введение в ООП с примерами на C# →

3.4. Интерфейсы

§ 40. Определение. Неформально можно сказать, что интерфейс – это аналог абстрактного класса, но 1) который содержит только абстрактные (без реализации) 53 открытые методы, 2) от которого допускается множественное наследование, 3) все методы которого должны быть переопределены в первом производном классе. Рассмотрим эти особенности на следующем примере.

На следующем рисунке приведена диаграмма UML: интерфейс изображается как класс, но помечается текстом > ; отношение реализации (наследования) интерфейса изображается прерывистой линией со стрелкой как при наследовании.

что такое интерфейс ооп. Смотреть фото что такое интерфейс ооп. Смотреть картинку что такое интерфейс ооп. Картинка про что такое интерфейс ооп. Фото что такое интерфейс ооп

Интерфейс (interface) – именованный перечень сигнатур открытых методов, который может быть унаследован другим интерфейсом или классом; первый наследующий класс должен переопределить все методы интерфейса; допускается множественное наследование от интерфейсов. О классе, наследующем интерфейс, говорят, что он реализует (implement) интерфейс и его методы.

Интерфейсы широко применяются в современной практике программирования, однако мы опустим обсуждение вопросов целесообразности использования в том или ином случае, а также выбора между интерфейсами и абстрактным классом. Ограничимся одним типичным примером – модульными тестами.

§ 41. Инверсия зависимости и модульные тесты. Автоматическое тестирование кода – область, где широко применяются интерфейсы. Это большая тема. Вкратце, идея заключается в том, чтобы написать специальный код (метод), который будет проверять корректность выполнения отдельных методов приложения. Такой специальный код (метод) называется модульным тестом (unit test).

Рассмотрим следующий пример. Положим, мы пишем программу, которая анализирует траектории движения общественного транспорта. На автобусах стоят устройства местоопределения ГЛОНАСС, которые по сети GSM присылают данные о текущем местоположении на сервер. Специальное приложение на сервере получает эти данные и записывает в базу данных. Наше приложение по запросу пользователя считывает пройденный путь из базы данных и выполняет некоторый анализ, например, рассчитывает длину пути за последний час.

Общее решение – для которого и используются интерфейсы – заключается в создании класса-заглушки ( stub ), который имитирует поведение объекта dataProvider без реального обращения к базе данных, тем самым разрывая зависимость от источника данных.

Таким образом, интерфейс позволяет подменить объекты, создающие зависимости и затрудняющие тестирование. На следующем рисунке показана диаграмма классов для варианта без интерфейса (вверху) и с интерфейсом (внизу).

что такое интерфейс ооп. Смотреть фото что такое интерфейс ооп. Смотреть картинку что такое интерфейс ооп. Картинка про что такое интерфейс ооп. Фото что такое интерфейс ооп

Таким образом, рассмотренное решение эффективно не только для реализации модульных тестов, но и, в целом, делает архитектуру более гибкой, снижая зависимость частей программы друг от друга. Более того, эта возможность часто отмечается как ключевая возможность объектно-ориентированного программирования: «That is the power that OO provides. That’s what OO is really all about – at least from the architect’s point of view (dependency inversion). This is one reason that object-oriented development has become such an important paradigm in recent decades.» [Мартин 11]

Вопросы и задания

Что такое интерфейс? В чем отличие интерфейса от абстрактного класса?

Положим в предыдущей задаче метод A.Clone имеет следующую реализацию:

Как при этом изменится решение задачи и изменится ли оно?

** Познакомьтесь с инструментами модульного тестирования MSTest или NUnit.

53. Некоторые языки с оговорками допускают задание реализации метода в интерфейсе. Например, C# позволяет задавать реализацию по умолчанию (явный способ) или реализацию через механизм расширений (косвенный способ). Однако здесь при первом знакомстве с интерфейсами мы не будем рассматривать эти возможности.

Источник

Интерфейсы в ООП на PHP

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

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

Фактически ваш родительский класс описывает потомков, то есть набор их публичных методов, обязательных для реализации.

То же самое касается другого программиста, работающего с вашим проектом. Пусть код класса-родителя писали вы, а затем ваш коллега решил создать еще одного потомка. У вашего коллеги также не получится потерять парочку методов.

Есть, однако, проблема: фактически мы сделали наш класс-родитель для того, чтобы писать в нем абстрактные публичные методы, но мы сами или наш коллега имеем возможность случайно добавить в этот класс не публичный метод или не абстрактный.

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

Нельзя создать объект интерфейса. Все методы интерфейса должны быть объявлены как public и не должны иметь реализации. У интерфейса могут быть только методы, но не свойства. Нельзя также сделать интерфейс и класс с одним и тем же названием.

Попробуем на практике

Давайте попробуем на практике. Решим задачу на фигуры из предыдущего рока, но уже используя интерфейсы, а не абстрактные классы.

Итак, теперь у нас дан интерфейс Figure :

Как это работает: если забыть реализовать какой-нибудь метод, описанный в интерфейсе, PHP выдаст нам фатальную ошибку. Давайте реализуем также класс Rectangle :

Замечание

Источник

Интерфейсы vs. классы

Обсуждая с различными людьми — в большинстве своём опытными разработчиками — классический труд «Приёмы объектно-ориентированного проектирования. Паттерны проектирования» Гаммы, Хелма и др., я с изумлением встретил полное непонимание одного из базовых подходов ООП — различия классов и интерфейсов.

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

Поэтому я попытался систематизировать своё понимание вопроса в этой заметке.

Главное отличие класса от интерфейса — в том, что класс состоит из интерфейса и реализации.

Любой класс всегда неявно объявляет свой интерфейс — то, что доступно при использовании класса извне. Если у нас есть класс Ключ и у него публичный метод Открыть, который вызывает приватные методы Вставить, Повернуть и Вынуть, то интерфейс класса Ключ состоит из метода Открыть. Когда мы унаследуем какой-то класс от класса Ключ, он унаследует этот интерфейс.

Кроме этого интерфейса, у класса есть также реализация — методы Вставить, Повернуть, Вынуть и их вызов в методе Открыть. Наследники Ключа наследуют вместе с интерфейсом и реализацию.

И вот здесь таятся проблемы. Предположим, у нас есть некая модель, которая предполагает использование ключа для открытия двери. Она знает интерфейс Ключа и поэтому вызывает метод Открыть.

Но, предположим, некоторые двери открываются не таким вот поворотным ключом, а магнитной карточкой — которая ведь тоже по своей сути ключ! Интерфейс этой карточки никак принципиально не отличается от интерфейса обычного ключа — можно Открыть ключом, а можно Открыть карточкой.

И мы хотим сделать класс Магнитную Карточку, который тоже будет содержать интерфейс Ключа. Для этого мы унаследуем Магнитную Карточку от Ключа. Но вместе с интерфейсом унаследовалась и реализация, которая в методе Открыть вызывает методы Вставить, Повернуть и Вынуть — а это совершенно не подходит для Магнитной Карточки.

Нам придётся самое меньшее перегружать в Магнитной Карточке реализацию метода Открыть, используя уже последовательность Вставить, Провести и Вынуть. Это уже плохо, потому что мы не знаем детали реализации класса Ключ — вдруг мы упустили какое-то очень важное изменение данных, которое должно было быть сделано — и было сделано в методе Ключ:: Открыть? Нам придётся лезть во внутреннюю реализацию Ключа и смотреть, что и как — даже если у нас есть такая техническая возможность (open source навсегда и так далее), это грубое нарушение инкапсуляции, которое ни к чему хорошему не приведёт.

Именно так и пишут Гамма и др.: наследование является нарушением инкапсуляции.

Можете попробовать самостоятельно поразмышлять над такими вопросами:
— Что делать с тем фактом, что Ключ вставляется просто в скважину, а Магнитная Карточка — обязательно сверху (не посередине и не снизу)?
— Что делать, когда нам понадобиться сделать Бесконтактную Карточку, которую надо не вставлять, а подносить?

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

Мы должны опираться на интерфейсы, а не классы.

Объявим интерфейс Ключ, содержащий метод Открыть.

Объявим класс Поворотный Ключ, реализующий интерфейс Ключ при помощи своих методов Вставить, Повернуть и Вынуть.

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

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

Вам может показаться странным, но это именно то, что отличает человека от животного — использование интерфейсов вместо классов. Вы наверняка помните классический опыт с обезьяной, которую приучили гасить огонь водой из ведёрка; а потом поставили ведёрко на плот посреди бассейна, но обезьяна всё равно бегала по мостику на плот и черпала воду из ведёрка, вместо того, чтобы черпать воду прямо из бассейна. То есть обезьянка использовала класс Вода-в-Ведёрке вместо интерфейса Вода (и даже больше, скажу по секрету: вместо интерфейса Средство-для-Тушения).

Когда мы мыслим классами — уподобляемся животным. Люди мыслят (и программируют) интерфейсами.

Использование интерфейсов даёт большие возможности. Например, класс может реализовывать несколько интерфейсов: класс Ключ-от-Домофона может содержать интерфейсы Ключ и Брелок.

Что касается наследования классов, которое, как вы помните, нарушает инкапсуляцию — часто вместо наследования лучше использовать делегирование и композицию. Не забыли Бесконтактную Карточку? Так хочется сделать её родственной Магнитной Карточке! (Например, чтобы знать, что их обе можно положить в Отделение-для-Карточек в Бумажнике.) Однако у них, кажется, нет ничего общего: интерфейс Ключ их роднит в той же мере, что и Поворотный Ключ с Ключом-от-Домофона.

Решение? Делаем класс (а может, и интерфейс — подумайте, что здесь подойдёт лучше) Карточка, реализующий интерфейс Ключ за счёт делегирования Магнитной Карточке либо же Бесконтактной Карточке. А чтобы узнать, что такое делегирование и композиция, а так же при чём тут абстрактная фабрика — обратитесь к книгам, посвящённым паттернам проектирования.

У использования интерфейсов вместо классов есть ещё много преимуществ. Вы сами сможете увидеть их на практике. Оставайтесь людьми!

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *