Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2007.11.25;
Скачать: [xml.tar.bz2];

Вниз

Visitor vs. Reflection   Найти похожие ветки 

 
Alkid ©   (2007-10-23 11:42) [0]

Дилемма, собственно, такая: есть некотрое количество объектов разных классов (с общим предком), экземпляры которых надо по-разному обрабатывать. Есть 2 пути:
1. Паттерн "Визитор"
2. Использование метаданных через оператор is (dynamic_cast<>() в C++) + пачка if-ов, либо паттерн "Стратегия".

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

Второй путь неинтрузивный, но полагается на работу с метаданными, т.е. будет медленнее. Крое того, зубры от программирования (Страуструп, GOF) считают это порочной практикой.

Ваши мнения на сий счёт?


 
Сусл ©   (2007-10-23 11:48) [1]


> Ваши мнения на сий счёт?

слишком мало информации :)
это все равно, что операцию по удалению аппендикса по телефону делать.


 
Сусл ©   (2007-10-23 11:48) [2]

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

хотя см [1]


 
Игорь Шевченко ©   (2007-10-23 11:54) [3]

1


 
ZeroDivide ©   (2007-10-23 11:57) [4]

А если применить паттерн "Мозги"... правда это интрузивный паттерн, т.е. требует реализации метода "Прямые руки"...

По сабжу: Выбор реализации зависит от того, что это за классы. Что они реализуют?


 
Сусл ©   (2007-10-23 12:06) [5]


> т.е. требует реализации метода Accept в каждом из "исследуемых"
> классов. Кроме того он требует наличия общего предка (что,
> пока, не является препятсвием)

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


 
Alkid ©   (2007-10-23 12:10) [6]

Что делать это всё будет - пока точно не ясно.

Вероятнее всего это будет интер-трепация абстрактного синтаксического дерева LISP-подобного DSL, в котором узлами и листами будут те самые классы, которые нужно обрабатывать, а интертрепатор должен будет "кушать" это дерево и производить разные (полезные по возможности) действия :)

Хотя "в реальности всё не так, как на самом деле", так что концепция ещё может поменяться :) Например - дать каждому узлу метод "Evaluate", что бы оне сам себя вычислял (но и тут есть свои барьеры).

А вообще этот пост задумывался не как просьба посоветовать в конкретной ситуации, а как попытка раскрутить народ на дискуссию по этой теме вообще.

Так что:

> Игорь Шевченко ©   (23.10.07 11:54) [3]
>
> 1

Можно получить более развёрнутый ответ?


 
Alkid ©   (2007-10-23 12:13) [7]


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

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


 
Игорь Шевченко ©   (2007-10-23 12:16) [8]

Alkid ©   (23.10.07 12:10) [6]


> Можно получить более развёрнутый ответ?


Можно. Какое именно слово развернуть ?


 
Alkid ©   (2007-10-23 12:18) [9]


> Можно. Какое именно слово развернуть ?

Слово "1" :)
А точнее, почему именно визитор, а не инспектирование класса + паттерн стратегия или набор if-ов?


 
Сусл ©   (2007-10-23 12:22) [10]

2автор
я помню на rsdn было много любителей пообщаться на эти темы, причем очень профессионально. Если не ошибаюсь в "проектировании".


 
Alkid ©   (2007-10-23 12:24) [11]


> 2автор
> я помню на rsdn было много любителей пообщаться на эти темы,
>  причем очень профессионально. Если не ошибаюсь в "проектировании".

RSDN-это да, но это та ещё помойка :) Там неуютно :)


 
Игорь Шевченко ©   (2007-10-23 12:32) [12]

Alkid ©   (23.10.07 12:18) [9]


> А точнее, почему именно визитор, а не инспектирование класса
> + паттерн стратегия или набор if-ов?


Лично мое скромное мнение - с visitor нагляднее. Работать с метаданными - значит перекладывать обнаружение ошибок с этапа компиляции на этап выполнения, стратегия - это те же if-ы, а набор if-ов есть зло по определению, ибо неясно и запутанно


 
Alkid ©   (2007-10-23 12:38) [13]


> Лично мое скромное мнение - с visitor нагляднее. Работать
> с метаданными - значит перекладывать обнаружение ошибок
> с этапа компиляции на этап выполнения, стратегия - это те
> же if-ы, а набор if-ов есть зло по определению, ибо неясно
> и запутанно

Про перекладывание с compile-time на run-time: +1.
Это, наверное, самый важный аргумент из всех прозвучавших.

Вообщем, по итогам состоявшегося кратного обсуждения, однозначно склонился в сторону Visitor"a.


 
pasha_golub ©   (2007-10-23 12:45) [14]

Простите, ребята. А шо такое Визитор?


 
Alkid ©   (2007-10-23 12:48) [15]


> Простите, ребята. А шо такое Визитор?
> <Цитата>

Паттерн проектирования программ.
Вот тут есть описание. Правда на языке вероятного противника:
http://en.wikipedia.org/wiki/Visitor_pattern


 
ZeroDivide ©   (2007-10-23 13:07) [16]


> Простите, ребята. А шо такое Визитор?


http://www.insidecpp.ru/patterns/visitor/

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

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

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

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


 
Игорь Шевченко ©   (2007-10-23 13:10) [17]


> Про перекладывание с compile-time на run-time: +1.
> Это, наверное, самый важный аргумент из всех прозвучавших.
>


Не так давно на sql.ru была дискуссия, кто как поля от DataSet использует.
Так умные люди используют persistent-поля (которые DataSetField: TxxxxField), а не FieldByName. Отчасти из тех же соображений, что компилятор в обращении FieldByName ошибку не обнаружит.


 
Alkid ©   (2007-10-23 13:22) [18]

Попробую поспорить со статьёй:

Вот тут мы определяем иерархию классов (Tree, Pine, Fir), базовый класс TreeVisitor и пару классов-визиторов.

class TreeVisitor
{
public:
 virtual void Process(Pine&) {}
 virtual void Process (Fir&) {}
}

class Tree
{
public:
 virtual void Accept(TreeVisitor&) = 0;
}

class Pine : public Tree
{
public:
 virtual void Accept(TreeVisitor& visitor)
 {
    visitor.Process(*this);
 }
}

class Fir: public Tree
{
public:
 virtual void Accept(TreeVisitor& visitor)
 {
    visitor.Process(*this);
 }
}

class SawPineVisitor : public TreeVisitor
{
public:
 virtual void Process(Pine& pine)
 {
    // Here we saw pine
 }
}

class DecoratePineAndSawFirVisitor : public TreeVisitor
{
 virtual void Process(Pine& pine)
 {
    // Here we decorate pine
 }
 virtual void Process(Fir& fir)
 {
    // Here we saw fir
 }
}


Как видим, о всех наследных классах знает только TreeVisitor.
Tree и его наследники знают только о TreeVisitor

Так что утверждение:

> Во-первых, базовому классу придется знать обо всех типах
> визиторов, которые он умеет принимать. В моем примере визитор
> — шаблонный класс. Однако и это не спасает от зависимостей.
>  Базовому инспектируемому классу необходимо знать о своих
> дочерних классах на уровне неполного объявления.  

Неверно. И зачем там шаблоны городили - непонятно


 
Игорь Шевченко ©   (2007-10-23 13:33) [19]


> Попробую поспорить со статьёй:


а что, на привычном народу языке написать впадлу ?


 
Alkid ©   (2007-10-23 13:33) [20]


> Не так давно на sql.ru была дискуссия, кто как поля от DataSet
> использует.
> Так умные люди используют persistent-поля (которые DataSetField:
>  TxxxxField), а не FieldByName. Отчасти из тех же соображений,
>  что компилятор в обращении FieldByName ошибку не обнаружит.

Это да. Хотя на прошлой моей работе (а я там на Delphi программировал по большей части) восновном юзались именно FieldByName.


 
Сусл ©   (2007-10-23 13:40) [21]

2автор.

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

еще просто так, то анализируй не ООП-приемы, а твою ситуацию.
Например, ответь на следующие вопрос.
1. Сколько предполагается посещаемых объектов.
2. Соклько предполагается посетителей (алгоритмов).
3. Есть ли вероятность внедрения нового посетителя.

Заметь, кстати, что весь этот GoF в основном имеет примерами текстовый редактор или мтератор и пр.

У переодически создается впечатление, что применимость некоторых (вернее так - НЕОБХОДИМОСТЬ) притянута за уши.


 
Alkid ©   (2007-10-23 13:41) [22]

Пишу для тех, кому впадлу читать не непривычом языке:

// Visitor base
type TTreeVisitor = class
 procedure Process(pine: TPine); virtual;  // Empty body
 procedure Process(fir   : TFir); virtual; // Empty body
end;

// Domain hierarchy
type TTree = class
  procedure Accept(visitor : TTreeVisitor);virtual;abstract;
end;

type TPine = class(TTree)
  procedure Accept(visitor : TTreeVisitor);override;
end;

procedure TPine.Accept(visitor : TTreeVisitor);
begin
 visitor.Process(Self);
end;

type TFir= class(TTree)
  procedure Accept(visitor : TTreeVisitor);override;
end;

procedure TFir.Accept(visitor : TTreeVisitor);
begin
 visitor.Process(Self);
end;

// Visitors
type TSawPineVisitor = class(TTreeVisitor)
 procedure Process(pine: TPine); override;
end;
procedure TSawPineVisitor.Process(pine: TPine);
begin
 // Here we saw pine
end;

type TDecoratePineAndSawFirVisitor = class(TTreeVisitor)
 procedure Process(pine: TPine); override;
end;

procedure TSawPineVisitor.Process(pine: TPine);
begin
 // Here we decorate pine
end;

procedure TSawPineVisitor.Process(fir: TFir);
begin
 // Here we saw fir
end;


 
Игорь Шевченко ©   (2007-10-23 13:48) [23]


> > Во-первых, базовому классу придется знать обо всех типах
>
> > визиторов, которые он умеет принимать. В моем примере
> визитор
> > — шаблонный класс. Однако и это не спасает от зависимостей.
>
> >  Базовому инспектируемому классу необходимо знать о своих
>
> > дочерних классах на уровне неполного объявления.  


Это утверждение двоякое. Если Visitor-ы имеют общего предка, то достаточно знаний о предке. Ну а если нет, тогда, разумеется надо знать о всех родоначальниках иерархий visitor-ов.

Кстати, очень советую почитать документацию по tiopf (http://tiopf.sourceforge.net/)
- они аспект использования visitor-ов в Delphi очень подробно разжевывают с картинками.

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


 
Alkid ©   (2007-10-23 13:50) [24]


> еще просто так, то анализируй не ООП-приемы, а твою ситуацию.
>
> Например, ответь на следующие вопрос.
> 1. Сколько предполагается посещаемых объектов.
> 2. Соклько предполагается посетителей (алгоритмов).
> 3. Есть ли вероятность внедрения нового посетителя.

Посещаемых объектов (узлов AST) предполагается тысячи экземпляров примерно двух десятков классов.
Посетителей предполагается несколько десятков экземпляров 3-4 классов.
Что есть "внедрение нового посетителя"?


> У переодически создается впечатление, что применимость некоторых
> (вернее так - НЕОБХОДИМОСТЬ) притянута за уши.

Это да, это есть. Собственно, излишнее приминение паттернов само по себе явялется общепризнанным антипаттерном.


 
Alkid ©   (2007-10-23 13:54) [25]


> Кстати, очень советую почитать документацию по tiopf (http:
> //tiopf.sourceforge.net/)
> - они аспект использования visitor-ов в Delphi очень подробно
> разжевывают с картинками.

Это которое "The Visitor Pattern Framework"?
Сейчас ознакомлюсь.


 
Игорь Шевченко ©   (2007-10-23 13:56) [26]

Alkid ©   (23.10.07 13:54) [25]


> Это которое "The Visitor Pattern Framework"?


Это которое Object Persistence Framework for Free Pascal & Delphi.
Буковки Ti - это по институту вроде.


 
boriskb ©   (2007-10-23 14:02) [27]

> Не так давно на sql.ru была дискуссия, кто как поля от DataSet
> использует


Ахринеть! (с)

До сих пор дискуссии?
Лет 5 назад про это в жарком споре участвовал.


 
Alkid ©   (2007-10-23 14:08) [28]


> До сих пор дискуссии?
> Лет 5 назад про это в жарком споре участвовал.

Лет 5 назад тут меня ещё не было :)


 
reonid ©   (2007-10-23 14:23) [29]

>Посещаемых объектов (узлов AST) предполагается тысячи экземпляров >примерно двух десятков классов.
>Посетителей предполагается несколько десятков экземпляров 3-4 классов.

Если у тебя два десятка посещаемых классов
и три-четыре операции - то не понятно, зачем там нужен визитёр.
Сделай 3-4 виртуальные функции и всё.

А количество экземпляров тут вообще не в кассу.


 
Kolan ©   (2007-10-23 14:39) [30]

Я за посетителя.
&laquo;пачка if-ов&raquo; &#151; в любом случае bed smell© самизнаетекто :)


 
Джо ©   (2007-10-23 14:42) [31]

> [30] Kolan ©   (23.10.07 14:39)
любом случае bed smell© самизнаетекто
> :)

Именно «постельный запах»? ;)


 
clickmaker ©   (2007-10-23 14:45) [32]

а я думал, что только "постельные сцены" бывают )


 
Kolan ©   (2007-10-23 14:49) [33]

>
> Именно «постельный запах»? ;)

Учусь печатать вслепую :)


> а я думал, что только &laquo;постельные сцены&raquo; бывают )

Так, хорошь прикалываться :)

bad ессно имелось ввиду.


 
Alkid ©   (2007-10-23 14:53) [34]


> Если у тебя два десятка посещаемых классов
> и три-четыре операции - то не понятно, зачем там нужен визитёр.
>
> Сделай 3-4 виртуальные функции и всё.
>
> А количество экземпляров тут вообще не в кассу.

Не скажи.  Один проход может занимать некоторое время. Одновременно может совершаться проход по одному дереву несколькими statefull-visitor`ами. Как реализовать такой независимый проход на виртуальных функциях самих классов в принципе понятно, но будет коряво.


 
Alkid ©   (2007-10-23 14:58) [35]


> Я за посетителя.
> «пачка if-ов» — в любом случае bed smell© самизнаетекто
> :)

Всё относительно. Я видел как люди городили стратегии там, где всё решалось switch"eм с 3 (!!) вариантами и 3-4 строчками в каждом из них. На вопрос "а зачем писать с три короба, когда можно сделать просто и понятно" мне говорили "ну это же паттерны, это круто!".

С другой стороны даже чаще видел огромные простыни методов класса в каждом из котороых был мега-switch(Mode).


 
Kolan ©   (2007-10-23 15:00) [36]

И еще по поводу &laquo;функцияций самих классов&raquo;. Имхо как только возникают разные алгоритмы обхода, то паттерн Information Expert не действует, и надо основываться на паттерне Protcted Variations, а посетитель стедсь более уместен в плане добавления новых&#133имхо&#133


 
Игорь Шевченко ©   (2007-10-23 15:02) [37]

Alkid ©   (23.10.07 14:58) [35]

Любой алгоритм должен быть реализован минимальным количеством строк ясного кода
(с)


 
Alkid ©   (2007-10-23 15:03) [38]


> И еще по поводу «функцияций самих классов». Имхо как только
> возникают разные алгоритмы обхода, то паттерн Information
> Expert не действует, и надо основываться на паттерне Protcted
> Variations, а посетитель стедсь более уместен в плане добавления
> новых…имхо…

Pls, дай ссылки с описанием упомянутых тобой паттернов.


 
Kolan ©   (2007-10-23 15:08) [39]


> &laquo;ну это же паттерны, это круто!&raquo;.

Это признак анти паттерна, имхо.


 
Alkid ©   (2007-10-23 15:09) [40]


> Любой алгоритм должен быть реализован минимальным количеством
> строк ясного кода
> (с)

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

Я сам переболел этим (к счастью без серзёного ущерба для кого-либо). А, вот, на моём текущем месте работы недавно уволился архитектор, по милости которого фирма вбухала огромные средства во Framework, который в итоге оказался неприспособлен для решения реальных задач.



Страницы: 1 2 вся ветка

Форум: "Прочее";
Текущий архив: 2007.11.25;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.054 c
2-1193840686
Ламер
2007-10-31 17:24
2007.11.25
Команды посылаемые модемом серверу


2-1194086944
Riply
2007-11-03 13:49
2007.11.25
Конструкция record`а.


1-1189049650
Nikfel
2007-09-06 07:34
2007.11.25
Добавление пункта в системное контекстное меню эксплорера


15-1192820360
NotWinProgrammer
2007-10-19 22:59
2007.11.25
для меня открытие


2-1194125113
nWinter
2007-11-04 00:25
2007.11.25
PopupMenu





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский