Watch, Follow, &
Connect with Us

Vsevolod Leonov

Delphi полиморфизм

Объяснение - мать учения

На территории русскоговорящей части земного шара в большом количестве циркулируют бумажные книги по Delphi. Также доступны и чисто электронные издания. Я держу в руках книгу по Delphi, в ней более 1024 страниц. Слову полиморфизм посвящено 5 строк. Компоненту TButton - 96 строк + 2 рисунка, включая 2 примера в исходном коде. Понимание кнопок в ~20  раз важнее?

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

Северное сияние

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

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

Эзотерика

Задайте вопрос про полиморфизм другу, преподавателю, интернету и т.д. и вы поймете, что это знание суть эзотерично. Вам расскажут массу всего на тему «надо сначала год проработать полиморфистом, а потом поймешь». А книжный вариант текста закончится контрольной фразой «…для решения двух или более схожих, но технически различных задач». На самом деле, программирование - инженерная наука, чудеса и творчество начинаются уже на базе легко объяснимых понятий. Без эзотерики.

С высоты мышиной возни

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

Какую проблему решает полиморфизм

А какие проблемы есть у разработчиков? Нет, проблему зарплаты полиморфизм не решает. По крайней мере, впрямую. А вот при помощи полиморфизма можно создавать хорошие большие программы, минимизируя сложность кода. А кому нужен простой, но мощный код? Наверное, всем. Программисту, чтобы чувствовать себя счастливым от качественного кода, разработанного самим собой. Пользователю, чтобы не посылать в пространство проклятья по-поводу очередного бага. Человеку, который платит зарплату программисту, т.к. простой, но мощный код проще и быстрее (читай, дешевле) сопровождать, модифицировать и развивать. Хорошо, ответьте на вопрос, почему «плохо использовать глобальные переменные». Смысл ответов на эти два вопроса очень близок.

Полиморфизм - дело добровольное

- А можно не пользоваться полиморфизмом?

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

- А вдруг я использую полиморфизм, но не знаю об этом?

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

- Я спросил своего друга, профессионального программиста, про полиморфизм. Он ответил уклончиво. Он что, сам не знает?

- Знает. Но это тяжело объяснить. Поэтому и появился данный пост (чтобы никто не говорил, что Delphi множит программистов-незнаек).

Я уже прочитал многобукв, но не ощутил ценность данного поста

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

Я уже устал читать

А я - писать! Но что поделаешь, если в книгах по Delphi этому посвящено строк в разы меньше, чем описанию свойств компонента TLabel. Когда-то ведь надо рассмотреть это подробно.

Даю автору последний шанс

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

Входит начальник в офис. Громким голосом кричит: «работать»! Секретарша застучала по клавиатуре, менеджер схватился за телефонную трубку, юрист открыл папку, программист сделал унылое лицо и запустил браузер. (Только что вы увидели полиморфизм. Не так поразительно, как северное сияние, но мы же не ученые-полярники!)

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

Утром я зашел на кухню. Я включил кофеварку, я включил микроволновую печь, я включил стереосистему. Каждый аппарат начал работать по-своему, но у всех есть кнопка «вкл», которая приводит к «…решению двух или более схожих, но технически различных задач» (это - определение из книги, теперь оно становится более… нет, не понятным, но наглядным).

Генерал зычно крикнул, а в гарнитурах солдат 21-го века отдалось зычное «огонь»! Пулеметчик застрочил из пулемета. Гранатометчик выстрелил из базуки. Артиллерист дернул за веревочку. Виртуальный боец нажал на кнопку джойстика.

Где тут полиморфизм

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

Заходит начальник в офис. И начинает лихорадочно и сумбурно бормотать: «секретарша - набивай текст», «менеджер - звони и договаривайся», «юрист - поработай с документами», «программист - займись хоть каким-нибудь делом (я всё равно не знаю, что ты делаешь)».

Дирижер имеет много рук, каждая из которых руководит отдельными группами музыкантов.

Кофеварка, микроволновая печка, стереосистема имеют разные кнопки для включения (ручки, рычажки, выключатели, тумблеры с разными иконками).

Генерал…. сами догадались. Один из критических случаев полиморфизма. Зато полиморфизм в армии помогает выигрывать сражения.

Скучновато

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

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

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

Хватит грузить, хочу программировать

Захотелось устроить «северное сияние вручную»? Сначала нужно увидеть, как это делаю взрослые. В смысле, как взрослые «занимаются полиморфизмом». Но сначала предупреждение. Как мы уже договорились, полиморфизм полезен (и нагляден) в случае сложного кода. Поэтому привести простой пример нереально. Поэтому приведенный пример будет чуть сложнее, чем включить кофеварку. Но проще, чем сыграть на скрипке. Где-то на уровне «погонять гоблинов по карте».

for i  := 0 to Army.SelectedUnitCount-1 do
begin
    Army.GetSelectedUnit(i).Attack(x, y);
end;

Поищем полиморфизм вместе. Сначала воспользуемся переводчиком с Delphi на русский.

Армия! По порядку рассчитайся! Нумерацию начать с 0!
Для каждого по счету выбранного бойца, входящего в состав моей армии! Атаковать цель в точке (x, y)!

Где полиморфизм? Только в одном месте. Там где «каждому выбранному бойцу атаковать точку». Если вы понимаете разницу между «бойцом» и «гоблином» («орком» или «эльфом»), то вы видите полиморфизм. Ко всем этим достойным персонажам мы обращаемся не по их типовой принадлежности типа «эй ты, эльф номер 13, атакуй точку (x, y)», а по-другому. Полиморфно.

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

Полиморфизм не может быть таким простым

Да ну! Как раз полиморфизм и есть «сама простота». А вот без полиморфизма, жизнь программиста была бы сложнее. Например, указанный выше код без полиморфизма стал бы таким, как показано ниже.

for i := 0 to Army.Goblins.SelectedUnitCount-1 do
begin
    Army.Goblins.GetSelectedUnit(i).MoveTo(x, y);
end;

for i := 0 to Army.Orcs.SelectedUnitCount-1 do
begin
    Army.Orcs.GetSelectedUnit(i).MoveTo(x, y);
end;

for i := 0 to Army.Dwarfs.SelectedUnitCount-1 do
begin
    Army.Dwarfs.GetSelectedUnit(i).MoveTo(x, y);
end;

for i := 0 to Army.Elfs.SelectedUnitCount-1 do
begin
    Army.Elfs.GetSelectedUnit(i).MoveTo(x, y);
end;

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

Хотелось бы самому написать полиморфный код

Легко. Для этого нужно понять, как обеспечивается полиморфизм в Delphi. Нужно создать иерархию классов и применить виртуальные методы. А потом породить объекты и обращаться к ним при помощи полиморфных ссылок. Хороший комментарий к этому посту поможет мне найти силы отозваться следующей статьей на тему «разработка игры для иллюстрации парадигм ООП».

Полиморфизм в Delphi

Полиморфный код в Delphi может отличаться от подобной техники, применимой в других языках программирования. Если вы используете C++ Builder, то код будет другой, но только по виду, но не по сути.

А как насчет самой Delphi изнутри? Не так просто, как многие пишут об этом. Например,

procedure TForm1.Button1Click(Sender : TObject);

как ни странно, ни разу не является иллюстрацией полиморфизма!

Нарушение полиморфизма

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

Или возможно? :)

Зачем и как

Зачем более-менее понятно. Нужно сделать код более прозрачным и более близким к образу мышления человека. И то, и то есть "снижение затрат на модификацию системы" (в плане развития).

На вопрос "как" ответом может быть отдельная статья. Это когда мы затронем синтаксис языка Object Pascal/Delphi.  Об этом позже.

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

Posted by Vsevolod Leonov on December 24th, 2010 under begin |



11 Responses to “Delphi полиморфизм”

  1. Vadim Lou Says:

    Хорошую тему затронули. Из отличия реализаций полиморфизма в Delphi по отношению к другим языкам, платформам(.net; java) - это наличие полиморфизма для описания объектов, т.е для типов. Т.о. типом как описанием возможно манипулировать - передавать как абстрактную логику. На практике это всего лишь виртуальные классовые методы. Microsoft упорно не желает реализовывать эту часть полиморфизма в своих языках и платформах(.net). То что сделано в Chromium - это эмуляция - т.е. производительность такой реализации не блещет … Наверное это последний аргумент удерживающий меня в рядах Delphi-нистов :)

  2. Vitali M. Savin Says:

    Спасибо! Но, на мой взгляд, статья более подходит для тех кто полиморфизм уже понимает (чувствует). Для новичков было бы неплохо для понимания добавить описание классов и на их структуре как раз показать, откуда он (полиморфизм) вдруг взялся в этом конкретном примере с атакой.

  3. sw Says:

    Занятно :)

    Я же всегда, при объяснении полиморфизма, привожу стандартный пример с методом Draw.
    Пример можно взять из справки Delphi: Delphi Language Reference -> Virtual and dynamic methods.

    Кстати вот ещё одна тема, которую порой не могут объяснить Delphi-программисты: чем отличается virtual от dynamic?

  4. ZENsan Says:

    Virtual и Dynamic - идентичны. Отличаются только видом оптимизации. Virtual методы оптимизированы на скорость вызова, а Dynamic на минимальное использование памяти. И по моему это многие знают…

  5. Vsevolod Leonov Says:

    @Vitali M. Savin

    Ок, спасибо. Обязательно будет пост "с самого начала".

  6. Vsevolod Leonov Says:

    @sw

    Стандартный пример с методом Draw сильно завязан на метафору "графического редактора". И у людей сразу начинает складываться ложное понимание, что де "полиморфизм" нужен для написание вполне конкретного кода. Возможно, Вам с учениками везло больше :) Смысл данных диковатых примеров - показать, что программирование отражает реальную действительность (способ мышления), а не вводит некие свои парадигмы.

  7. sw Says:

    > ZENsan
    Одно дело знать, а другое дело - понимать, когда нужно применять virtual, а когда dynamic.
    Я вот, например, долгое время считал, что раз virtual работает быстрее, то на dynamic можно "забить" (ведь сейчас объёмы памяти практически не ограничены несколькими сотнями килобайтов). И не понимал, когда использовать dynamic. И только с опытом, ну и плюс с "ковырянием" и осознанием исходников VCL, пришло понимание сути вопроса.

    > Vsevolod Leonov
    Возможно Вы правы, я не психолог. Однако для меня пример с Draw и с оговоркой, что мол не только в графике такое можно использовать - было вполне достаточно для …. ну сначала я был просто восхищён! Правда, я ведь начинал с процедурных языков программирования, и переход на ООП был уже с некоторым багажом знаний и опыта…
    А вот начинающим программистам, которые начинают сразу с ООП - так сразу и не понятно, зачем оно вообще всё это нужно…
    Поэтому такие статьи безусловно необходимы. :)

  8. Vsevolod Leonov » FireMonkey - анимация, шаг 1 Says:

    [...] предыдущих постах (полиморфизм, инкапсуляция) я пытался обходиться "без [...]

  9. Homepage Says:

    … [Trackback] …

    [...] Informations on that Topic: blogs.embarcadero.com/vsevolodleonov/2010/12/24/delphipoly-2/ [...] …

  10. Alexander Alexeev Says:

    Немного более технической информации по полиморфизму в Delphi (включая разницу virtual/dynamic и RTTI): http://www.transl-gunsmoker.ru/2011/07/polymorphism-ad-nauseum.html

  11. Vsevolod Leonov Says:

    Спасибо, Александр!
    Просто великолепный пост. С твоего позволения я ссылку внесу в текст.

Leave a Comment



Server Response from: BLOGS1