примеры полиморфизма в жизни

Полиморфизм для начинающих

Постановка задачи

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

Самые простые варианты, которые приходят в голову — написать три отдельных класса и работать с ними. Или написать один класс, в которым будут все свойства, присущие всем трем типам публикаций, а задействоваться будут только нужные. Но ведь для разных типов аналогичные по логике методы должны работать по-разному. Делать несколько однотипных методов для разных типов (get_news, get_announcements, get_articles) — это уже совсем неграмотно. Тут нам и поможет полиморфизм.

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

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

// а этот метод должен напечатать публикацию, но мы не знаем, как именно это сделать, и потому объявляем его абстрактным
abstract public function do_print ();
>

Производные классы

Теперь можно перейти к созданию производных классов, которые и реализуют недостающую функциональность.

Теперь об использовании

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

Вот и все. Легким движением руки брюки превращаются в элегантные шорты :-).

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

Немного теории

Источник

Для чего нужен полиморфизм?

Я понял что такое:
Инкапсуляция — Наследование — Полиморфизм — Абстракция

Я понял для чего:
Инкапсуляция — Наследование — Абстракция

Но я не понял зачем и для чего — ПОЛИМОРФИЗМ

И не понимаю суть примеров которые приводят:
Создают новую функцию в которую помещается вызов определенного метода.
А ведь я могу и без написания доп функции обращаться к ее методу и исходя из примера так даже кода будет меньше.

примеры полиморфизма в жизни. Смотреть фото примеры полиморфизма в жизни. Смотреть картинку примеры полиморфизма в жизни. Картинка про примеры полиморфизма в жизни. Фото примеры полиморфизма в жизни

В общем случае полиморфизм нужен для переиспользования кода. Соблюдения практик SOLID и DRY не возможно без полиморфизма. Например в языке Go отсутствие полиморфизма в любом виде приводит к загрязнению кодовой базы и большому количеству копипасты.

И еще, из моего ответа, может сложится мнение, что полиморфизм не применим к языкам с динамической типизацией, например к Python. На самом деле это не так, в ЯП с динамической типизацией полиморфизм наоборот возведен в абсолют.

UPD: Примеры:
правда я не шибко хорошо знаю конкретно Python, поэтому абстрактно напишу псевдокод:

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

ad-hoc полиморфизм, это про перегрузку функций, пусть мы хотим функцию print которая умеет печатать числа и строки:

Источник

Примеры полиморфизма в реальной жизни

На собеседовании спрашивают: «Приведите примеры полиморфизма в реальной жизни».

Что именно они хотят услышать? Вижу тут два варианта: либо рассуждать о полиморфизме в отрыве от программирования(сабтайпинг, дженерики, ad hoc), либо пытаться внести все это в реальную жизни(например, если принтер может печатать текст, картинки, графики и тд. У него определен интерфейс печатать, а что именнно уже не так важно).

Какой пример привели бы вы?

Помощь в написании контрольных, курсовых и дипломных работ здесь.

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

Задачка из реальной жизни
Всем добрый вечер. Задачка из моей реальной жизни: Я болею эпилепсией, но тк живу в долбаной.

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

Решение

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

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

Решение

Добавлено через 3 минуты
По аналогии с предыдущим примером можно придумать кучу других аналогий из жизни:
Дверные петли.
Дверные замки (с разными личинками и ручками)
Монетоприемник в каком-нибудь продающем автомате.
В общем, только время и необходимость может ограничить полет вашей фантазии.

Источник

Когда полиморфизм терпит неудачу

Вообще говоря, я признаю, что использование instanceof и его аналогов обычно является следствием недостаточных навыков ООП проектирования. Полиморфизм лучше проверок типов. Он делает код гибче и понятнее. Однако есть по крайней мере один распространенный случай, когда вы точно не сможете использовать полиморфизм. Причем случай этот распостранен настолько, что может уже считаться паттерном. Я бы с удовольствием применил в нем полиморфизм, честно. И если вы знаете как это сделать — расскажите мне. Но не думаю что это возможно. По крайней мере точно не в статических языках типа Java или C++.

Определение полиморфизма

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

В языках программирования ориентированных на производительность, таких как C++, Java или OCaml, методам ставятся в соответствие числа, а затем для каждого класса создается таблица его методов. По которой и производится поиск во время выполнения. В языках же отдающих предпочтение гибкости и динамизму, поиск осуществляется не среди чисел, а среди хэшированных названий методов. В остальном эти два подхода практически совпадают.

Полиморфизм в действии

В качестве примера давайте взглянем на классическую задачу про вычисление математического выражения, часто встречающуюся на собеседованиях. Впервые её применил Рон Браунштейн в Амазоне (насколько я знаю). Задание является достаточно комплексным и позволяет проверить владение многими важными навыками. Это и ООП проектирование, и рекурсия, и двоичные деревья, и полиморфизм на пару с динамической типизацией, и общее умение программировать, и даже (если вам вдруг захочется усложнить задачу по-максимуму) теория синтаксического анализа.

Итак, обдумывая эту задачу, кандидат в какой-то момент осознает, что если использовать только бинарные операции, такие как «+», «-», «*», «/», то арифметическое выражение можно представить в виде двоичного дерева. Все листья дерева будут числами, а все промежуточные узлы — операциями. Выражение же будет вычисляться путем обхода дерева. Если соискатель не может самостоятельно прийти к такому решению, вы можете деликатно намекнуть. Или, если дела совсем плохи, сказать в лоб. Ведь даже после этого задача все равно останется интересной.

Первая ее половина, которую некоторые люди (чьи имена я унесу с собой в могилу, но чьи инициалы Вилли Льюис) считают Необходимым Требованием Для Желающих Называть Себя Разработчиком И Работать В Амазоне, на самом деле достаточно сложна. Вопрос здесь заключается в том как перейти от строки с арифметическим выражением, такой как «2 + (2)», к дереву выражений. И это серьезный вопрос.

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

Вы будете поражены как многих испытуемых этот этап ставит в тупик.

По иронии судьбы (как вы увидите в дальнейшем), решение с полиморфизмом идеально подходит для расширяемой системы. Если вы хотите добавлять новые функции без необходимости перекомпилировать все от и до и, в частности, без необходимости добавлять все новые и новые кейсы в ваш Гигантский Оператор Свитч Состоящий Из 500 Кейсов, то вам просто придется использовать полиморфизм.

Троекратное полиморфное ура в честь полиморфизма

Таким образом, полиморфизм, так или иначе, но кажется полезным. Самым удачным его применением, пожалуй, можно назвать полиморфный оператор вывода print. Если вы программируете на Java, Python, Ruby или любом другом «настоящем» объектно-ориентированном языке, то наверняка считаете его само собой разумеющимся. Вы просите объект распечатать себя и, ей-богу, он это делает. Каждый объект сообщает о себе ровно столько, сколько вам нужно знать о его внутреннем состоянии. Это очень полезно для отладки, трассировки, протоколирования и, возможно, даже документирования.

(Риторический вопрос: почему мы выбираем C++ или Perl? Это два самых ужасных языка в мире! Мы могли бы с таким же успехом применять Pascal или Cobol, неужели не ясно?)

Между прочим, полиморфный print — это главная причина почему я не пишу в последнее время про OCaml. По мотивам, которые я пока что до конца не осознал, но которые определенно находятся в списке Самых Невменяемых Мотивов Проектировщиков Языков, в OCaml нет полиморфного print ’а. Поэтому вы не можете выводить произвольные объекты на консоль для отладки. Я пытаюсь верить, что это понадобилось для достижения легендарной, превосходящей даже C++, производительности. Потому что любая другая причина была бы чудовищным оскорблением для юзабилити. Что ж, зато у них есть дебаггер способный возвращать программу назад во времени. Он определенно еще не раз пригодится.

Итак, все мы любим полиморфизм. Это альтернатива микроменеджменту. Вы просите объекты что-то сделать не говоря как это сделать, и они послушно подчиняются. Проводя день за онлайн просмотром клипов Strong Bad. Ох уж эти глупые объекты! Невозможно их не любить!

Но полиморфизм, как и все достойные герои, имеет и Темную Сторону. Конечно, не настолько темную как у Энакина Скайуокера, но тем не менее.

Парадокс полиморфизма

Использование полиморфизма предполагает редко произносимое вслух, но очень важное условие: у вас должна быть возможность изменять код и в дальнейшем. Ведь по крайней мере в статически типизированных языках, таких как Java и C++, в ходе добавления полиморфного метода требуется перекомпилировать все классы реализующие этот метод. А это, в свою очередь, означает что вам нужно иметь доступ к их исходному коду. А также возможность его модифицировать.

Есть определенный класс систем, для которых это невыполнимо — так называемые расширяемые системы.

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

Что-то подсказывает мне, что и веб-сервисы находятся в одной лодке с онлайн играми.

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

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

Суть проблемы

Чтобы разговор стал более конкретным, давайте вернемся к примеру с онлайн играми. Предположим, вы отлично все спроектировали и опубликовали API и классы для создания и управления заклинаниями, монстрами и другими игровыми объектами. Предположим, у вас есть большая база монстров. Уверен, вы можете это вообразить если постараетесь.

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

Пусть единственным смыслом жизни нашего Оценочного Эльфа будет оглашение того, нравятся ли ему другие монстры или нет. Он сидит на вашем плече и всякий раз когда вы встречаете, скажем, Орка, он кровожадно кричит: «Я ненавижу орков. Аааааааа. » (Между прочим, именно такие чувства я испытываю по отношению к С++)

Черт! Даже звучит безумно глупо. Но это и есть истинно полиморфный подход, не так ли? Если есть группа похожих объектов (в нашем случае, монстров), и все они должны различным способом реагировать на одну и ту же ситуацию, то вы добавляете им виртуальный метод и реализуете его по-разному для разных объектов. Верно?

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

Насколько я знаю (а я не претендую на лавры хорошего дизайнера, просто хочу найти правильный ответ), верным решение является динамическое определение типов. Код будет выглядеть как-то так:

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

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

Ruby загрузит все перечисленные классы, если они еще не загружены, и добавит ваш метод к каждому из них. Это очень крутая возможность, вообще говоря.

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

Я думаю, если можно было бы каким-то образом перебрать все классы в системе и проверить, являются ли они потомками Монстра, то все решилось бы несколькими строчками кода. В Ruby, бьюсь об заклад, это возможно… но только для уже загруженных классов. Для классов все еще находящихся на диске это не сработает! Наверняка можно обойти и эту проблему, но ведь кроме диска существует еще и сеть…

Впрочем, необходимость в поведении по умолчанию еще не самое плохое. Есть гораздо более серьезные минусы. Скажем, потокобезопасность. Она серьезно меня беспокоит — не думаю что семантика Ruby для потокобезопасности в этом случае четко определена. Будет ли синхронизация на уровне класса? Что случится с потоками экземпляров до-эльфовского класса? Я еще недостаточно знаю японский, чтобы разобраться в спецификациях или исходниках.

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

На самом деле все еще хуже. Попахивает Плохим Дизайном. Мы получаем ситуацию, при которой наблюдатель выносит своего рода суждения и мы прикрепляем код этих суждений к объектам наблюдения. Это выглядит, как если бы я ходил вокруг коллег со своего этажа и вручал каждому индивидуальный бейдж со словами: «Пожалуйста, никуда его не девайте. По нему я пойму, нравитесь вы мне или нет». В реальном мире все работает по-другому, а ООП, предполагается, должно моделировать именно реальный мир.

Пересмотр полиморфизма

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

Никоим образом! Вам пришлось бы добавить в код проверки времени выполнения:

Что ж, «тип» объекта является, в сущности, совокупностью его класса (который четко фиксирован и неизменен) и его свойств (которые могут быть как фиксированными, так и меняющимися во время выполнения). Это тема для отдельного разговора, но мне кажется, что тип определяется скорее свойствами, чем классами. Именно из-за врожденной негибкости последних. Но в «традиционных» языках типа C++ и Java такой подход сделал бы повторное использование кода чуть сложнее из-за отсутствия синтаксической поддержки делегирования. (Если вам вдруг показалось что это не имеет смысла, все в порядке: я допиваю уже третий бокал вина на пути к предпоследней стадии. Так что оставим эту тему для другой заметки.)

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

Подведение итогов

Итак, я надеюсь вы вынесли что-то полезное из сегодняшней заметки. Насчет себя я точно уверен. Например, я узнал, что поисковый движок Google и в самом деле достаточно умен чтобы исправить «Эникин Скайуокер» спросив «Возможно, вы имели в виду: Энакин Скайуокер?». Ох и надменные же парни! Не то чтобы авторские права принадлежали им.

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

Источник

Как на практике применяется полиморфизм?

примеры полиморфизма в жизни. Смотреть фото примеры полиморфизма в жизни. Смотреть картинку примеры полиморфизма в жизни. Картинка про примеры полиморфизма в жизни. Фото примеры полиморфизма в жизни

примеры полиморфизма в жизни. Смотреть фото примеры полиморфизма в жизни. Смотреть картинку примеры полиморфизма в жизни. Картинка про примеры полиморфизма в жизни. Фото примеры полиморфизма в жизни

4 ответа 4

Эта переменная может вызывать только методы, определённые в родительском классе, но если эти методы перекрыты в подклассе, то вызов метода переадресовывается в подкласс, в котором этот метод перекрыт.

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

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

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

Источник

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

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