Паттерны GoF - Visitor + bonus Acyclic Visitor (лекция)
Автор: MiF
<MiF> Visitor
<MiF> Назначение - описывает операцию над каждым объектом из семейства,
позволяя добавлять новые операции не меняя интерфейса
<MiF> То есть пусть у нас есть гомоморфная иерархия
<MiF> Очевидно, что добавить в нее новую операцию - это изменение интерфейса,
что сложно
<MiF> гомоморфная - с полностью абстрактным родителем :) (а вовсе не ахтунк)
<MiF> так вот, но при этом добавить новый класс в иерархию - просто
<MiF> Визитор - это паттерн, который все делает наоборот
<MiF> то есть его область применения - устойчивые иерархии (куда очень-очень
редко добавляются новые классы), в которые нужно очень часто добавлять новые
операции
<MiF> Кто не знаком - пока ниче не понял :)
<MiF> Потом все будет ясно
<MiF> Участники:
<MiF> 1. Visitor - объявляет операцию Visit для каждого класса из семейства
<MiF> Visitor - интерфейс
<MiF> 2. ConcreteVisitor - реализует его
<MiF> 3. Element (или Visitable) - определяет абстрактный Accept, который
принимает визитора как аргумент
<MiF> 4. ConcreteElement - реализует Accept
<MiF> О результатах я уже сказал - добавление операций без изменения интерфейс,
но при сложном добавлениее нового класса в иерархию
<MiF> *интерфейса
<MiF> пример кода необходим
<MiF> иначе ничего не ясно
<MiF> ушел писать
<CEMEH> Ничтоже сумнящеся предлагаю мое объяснение. Если кто-то действительно
не знает про Визиторы.
<CEMEH> Но все видимо знает. И мы ваще тут все сидим, ментально онанируем.
<CEMEH> *знают
<CEMEH> Но - давайте стараться для логов.
<MiF> :)
<unkier> отнють, я хочу увидеть примет кода
<MiF> Zeux наверное тоже :)
<unkier> это всё на благо, продолжайте
<kas> я бы лучше слушал про то где применяет народ
<kas> акромя скажем графа сцены.
<unkier> поддерживаю, реальные истории в студию
<CEMEH> У меня все таблицы в UI иерархичны.
<CEMEH> У многих treeview, даже у самых простых.
<CEMEH> По этому дереву ой как удобно ходить визиторами.
<CEMEH> Например, фильтр применить. Или суммарную стоимость выбранных частей
поддерева посчитать.
<kas> ага
<CEMEH> А остальные совсем явные - таки в обходе scene graph.
<CEMEH> Там интересной особенностью является то, что визитор может направлять
порядок обхода.
<CEMEH> Скажем, особым образом отсекать видимость.
<CEMEH> Или "выбирать" из нескольких путей.
<kas> ммм
<kas> ждём пример?
<CEMEH> От меня?
<kas> не
<kas> миф чтото обещал
<kas> код
<MiF> http://www.everfall.com/paste/id.php?q7j3gxknnljq
<kas> ну не знаю, не углубляясь в реализацию говорить вроде не очем больше
<MiF> ага, тут главное - реализация
<MiF> и ее косяки
<MiF> сейчас плавно перейдем в Acyclic Visitor
<kas> эээ
<kas> а зачем делал class IVisitable? :)
<MiF> чтобы можно было вызывать Accept не зная конкретных типов посещаемых
<kas> отнаследоваца забыл
<MiF> поправил
<unkier> во, теперь ясна всё
<MiF> короче все посмотрели?
<kas> ага, ну короче чтука мощная
<kas> ваще, патерны поведения мащны
<MiF> хотим добавить новую операцию - делаем нового потомка IVisitor'а
<MiF> теперь о косяках
<unkier> что дальше по курсу ?
<MiF> не, стойте
<MiF> это только начало по визитору :)
<unkier> bpdbyz.cm
<MiF> мысленно раскидайте это по файликах
<unkier> извиняюсь
<MiF> IVisitor'у нужны foward declarations всех классов иерархии
<MiF> IVisitable
<MiF> ему нужен foward declaration IVisitor
<MiF> Spell и SuperSpell должны знать о всех классах в иерархии
<MiF> короче циклические зависимости
<MiF> В результате большой косяк
<MiF> Допустим, нам захотелось добавить кроме вариора и гоблина еще мага
<MiF> что нужно сделать?
<MiF> 1. поменять интерфейс IVisitor
<MiF> 2. Добавить реализацию VisitMage в каждый конкретный визитор
<MiF> 3. Написать магу Accept
<MiF> короче проще яду выпить, если иерархия визиторов уже большая
<MiF> Да еще - цена обычного визитора - виртуальный вызов, что не напряжно
<MiF> Короче что делать с циклическими зависимостями?
<MiF> На помощь нам приходит Acyclic Visitor by Robert Martin кажется
<MiF> сейчас переделаю этот пример на ациклический
<MiF> а потом постану обобщенный вариант Acyclic Visitor'а :)
<MiF> йоу народ
<Padawan> ?
<kas> дада
<MiF> зажигаем
<MiF> :)
<unkier> угу
<unkier> лектор пишет на доске
<MiF> http://www.everfall.com/paste/id.php?ct6imencpe4q
<MiF> фтыкать
<kas> ага
<kas> РТТИ?
<MiF> да
<CEMEH> Ну я сразу спрошу - а как-же dynamic_cast это зло?
<MiF> зло
<MiF> но циклические зависимости - еще большее зло
<CEMEH> Т.е. мы боремся одним злом против другого зла?
<MiF> ага
<kas> в fwd_dcl?
<kas> ниспасают?
<CEMEH> Чорт. Я думал, паттерны - добро.
<kas> %)
<MiF> я написал, как сложно добавить класс в иерархию с обычным визитором
<kas> ну
<MiF> здесь циклических зависимостей нет
<kas> устойчивые иерархии жгут.
<MiF> ну представь
<MiF> была устойчивая вроде
<MiF> наплодил визиторов
<MiF> дофига
<MiF> и тут вдруг пришлось добавить новый класс все-таки
<kas> я не готов поставить галочку Use RTTI
<MiF> сколько мата услышат окружающие?
<kas> а кому щас легко...
<MiF> тут противостояние скорость/удобство поддержки
<kas> ну, ето понятно
<MiF> dynamic_cast не всегда критичен
<kas> типа все работы хараши, выбирай любую
<MiF> ага
<kas> ну, вот граф сцены
<kas> дохуа нод
<MiF> короче главное - Acyclic Visitor легко обобщается
<MiF> сейчас постану пример
<kas> в смысле обобщается?
<MiF> сейчас
<MiF> http://www.everfall.com/paste/id.php?bqa1eibc559f
<MiF> в таком виде поддерживать даже восьмиклассник сможет
<MiF> грубо говоря - добавление нового класса в иерархию за 5 секунд, нового
визитора за 10, не о чем помнить не надо
<MiF> то есть все строго
<MiF> вопросы есть?
<kas> нихт
<unkier> no
<MiF> Семен, не желаете ли добавить чего?
<MiF> все, поехали дальше
[added by Zeux: пример на Visitor: http://www.everfall.com/paste/id.php?0nvdbo0w58v7]
21 января 2006