информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Страшный баг в WindowsSpanning Tree Protocol: недокументированное применениеВсе любят мед
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Бэкдор в xz/liblzma, предназначенный... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
все доски
FAQ
IRC
новые сообщения
site updates
guestbook
beginners
sysadmin
programming
operating systems
theory
web building
software
hardware
networking
law
hacking
gadgets
job
dnet
humor
miscellaneous
scrap
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
[C++] Я так и не понял нескольких вещей 25.07.03 10:31  Число просмотров: 1720
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
amirul!

В очередной раз спасибо, что «оторвал» своё время и смог ответить на мой пост. Извини, что не сразу ответил на твои вопросы. Отвечу не в том порядке, в котором они следовали.

*****************************
>> Или обоснуй необходимость или не задавай вопрос, если сам все решил :-)
A:
Я сам ничего НЕ решил. Может и сложилось у тебя такое впечатление, возможно, из-за моего дурацкого стиля изложения.
Обосную:))), см. ниже весь вопрос и ответ.

Сразу скажу, что все дальнейшие мои ответы с налётом изыска в части возможности использования широковещательных рассылок, для уменьшения кода (разумеется, текста С++). Т.е. речь о попытке одним вызовом сделать дополнительную работу по части операций, которая не была предусмотрена в иерархической модели, о которой ты пишешь. Почему вдруг я перескакиваю с одного на другое? Я хочу последующим (не этим) своим постом подвести черту в топике. Он и так уже всем, кроме меня самого надоел. Там появится фигурант CMsgItem. Поэтому, отвечая на твои замечания, сразу буду говорить «в том ключе» (про полезность или неполезность «горизонталей»).

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

*****************************
>> Причиной было названо удобство организации передачи
>> сообщений в пределах КАЖДОЙ ИЗ ГРУПП. Однако всё это опять
>> только «косметика»…
> Здесь важно понимать, что ООП предполагает, что каждый объект сам знает…
A:
Объект знает, как себя перерисовать, передвинуть и т.д. Если использовать в дополнение к иерархической ООП-модели возможности бродкастинга («горизонталей»), то в ПРОСТЫХ реализациях всевозможных посредников бродкаст-рассылки, он (объект-наблюдатель) не узнает, когда ему будет РАЗРЕШЕНО Это сделать и КАК ИМЕННО, например, в зависимости от состояния субъекта наблюдателя. В том, что ты пишешь, такой проблемы не существует в принципе, поскольку в методе родителя программером «жестко» вбит порядок вызовов «одноимённых» методов детей, и возможно некая дополнительная обработка для разрешения коллизий, если таковая необходима.

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

*****************************
>>Приведу простой пример. Мы создали класс Животное и задали для него метод >>Передвигаться.>>Допустим есть какой-то контейнер Сцена, на которой находятся абстрактные >>Животные. Так вот, >>Сцена может знать, что какое-то животное нужно переместить куда-то. >>НО!!! Различные >>Животные перемещаются по разному. Поэтому Сцена не должна >>непосредственно управлять руками/ногами/ложноножками для этого перемещения, а просто >>говорить Животному Передвинуться (и т.д. вниз по иерархии).

A:
1) Я и не говорил, что «Сцена» должна «непосредственно управлять руками/ногами/ложноножками». Даже в первом посте про BCB++, контролами формы (ручки и ножки) управляют приват мембер-функции xxxContlos(). Там xxxContlos() – методы формы, которые управляют только своими мембер-контролами. Я и подумать не мог, что это надо уточнять.

«Удобно для оконной ФОРМЫ BC++ Builder с большим числом …». Форма BCB++– это класс: public TForm, например:
//---------------------------------------------------------------------------
class TfrmMonitor : public TForm
{
__published: // IDE-managed Components
TPanel *PanelMain;
TTreeView *TV;
…..// ~ 100 компонент контролов
…..
private: // User declarations
….
…..
void DisplayControls( int _mode);
void FillControls( int _mode);
public: // User declarations
__fastcall TfrmMonitor(TComponent* Owner);
};

void DisplayControls( int _mode), void FillControls( int _mode) – здесь даже приват, хотя и не суть. Не понимаю, откуда сложилось впечатление, что я хочу из методов одного класса управлять непаблик мемберами (контролами) другого класса.

«….Такую обработку несложно построить в BC++, т.к. все контролы являются ЧЛЕНАМИ КЛАССА формы приложения. Т.е из указанных выше функций (МЕТОДОВ ФОРМЫ) видны все контролы…. »

2) Думаю, что если дополнительно «Сцене» не контролировать, как будут выполняться методы «Передвинуться» животных, то этого в общем случае недостаточно. Животные знают, как им «по разному» передвигаться, в том смысле, что один из них будет объектно-ориентированно ползти, а другой – копытами стучать. Но если «Сцена» тупая, или мы СОЗНАТЕЛЬНО не хотим её усложнять из соображений снижения накладных расходов на программирование, то Животные при перемещении превратятся в стадо. При перемещении сами себя поубивают.

Хорошо, скажешь ты, пусть это умные животные (ведь цирк же, а не в тундра), т.е. каждый знает – КУДА ему идти. Например, слон знает, что по команде «Пошёл» - надо идти прямёхонько в оркестровую яму и только туда, потому, что только тогда зрителям будет смешно (цирк же), а мышь знает, что надо идти подальше от слона, к выходу (иначе тот разбушуется и покрошит всё). Но дело в том, что мышь не знает, что бежать ей следует ТОЛЬКО после слона. Если она побежит раньше, то слон, узрев это, в силу своей боязни на генетическом уровне мышей начнёт нервничать. Тогда, держись….

ПРОСТЫЕ модели, выполняющие доставку мессаг бродкастом, не умеют создавать и контролировать ОЧЕРЁДНОСТЬ обработки мессаг и РЕЗУЛЬТАТЫ ЭТОЙ ОБРАБОТКИ. Можно переложить это на виртуальные методы наблюдателя, усложнить протокол обработки мессаг и т.д. Но тогда это ну оооооооочень усложнит модель. Хочется получить простое решение.


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

A:
1) Согласен, если вместо «нельзя» - «как правило, не рекомендуется, крайне не желательно». Почему? Потому, что есть люди, которые юзают гольный API (это не я, но про таких знаю), и некоторые из них именно так и делают.

2) Там предлагается не глобальный обработчик для групп, а переопределённый виртуальный метод CMessanger. Он (его мембер-метод) и есть один «глобальный обработчик» для одной группы. Глобальным является объект, класс которого наследует от CMessanger. Каждой группе – по объекту CMessanger. В ЭТОМ смысле каждой группе – по глобальному обработчику. Группа – это избыточно связанные объекты CWnd, предназначенные для выполнения подзадачи. «Избыточно» –в том смысле, что и так существует связь объектов в MFC, вернее их иерархическая модель в голове программиста при использовании чисто ООП подхода (твоего). Эта избыточность проявляется в установлении «горизонталей», для обеспечения возможности бродкаста.
Если считать CMessanger медиатором, то он без синглентона, который знает всех своих участников группы.

3) Да, там есть слова про то, «…. что для каждой из групп определить свою пару ЧИСТО глобальных функций {FillControls_1, DisplayControls_1}, {FillControls_2, DisplayControls_2}, …». Но дальше по тексту идёт обоснование - почему так делать не надо. Это обоснование не с позиции ложной «обязательности» соответствия парадигмам ООП, а с позиции здравого смысла по мере развития идеи, поиска простых механизмов взаимодействия объектов.


*****************************
>>Нужно чтобы каждый КОНКРЕТНЫЙ объект САМ знал, как реагировать на тот или >>иной вызов. Обработчик должен быть методом класса (если речь об абстрактном >>классе, то виртуальным методом).

A:
Ещё раз хочу подчеркнуть то, что только что уже написал выше. «…КОНКРЕТНЫЙ объект САМ знал…» - работает только в четко разработанной иерархической модели. Если попытаться ввести «горизонтали», то это не будет работать в общем случае, например, при бродкасте. НЕ МОЖЕТ «…КОНКРЕТНЫЙ объект САМ знал…» в СЛОЖНЫХ моделях, в которых мы хоть на шаг отступаем от ООП. И без прозрачного мененджера тогда не обойтись. Под простой моделью я понимаю, например, некий хрестоматийный графический редактор. Там – да. Каждая фигура, для которой переопределён виртуальный метод, пусть «OnDraw», перересует себя правильно по своему усмотрению. Отличительная черта такой «простоты» в том, что объекту не надо ничего знать о том, перерисовали себя остальные объекты (объекты графической базы), или нет, и как. Поэтому-то простота модели порождает простоту реализации – возможность отрисовки всех объектов п р о с т ы м б р о д к а с т о м. Для моего случая, там где можно, ЭТО используется, чтобы не перегружать логику приложения.

Например, очевидно, что сообщения UM_ERASE могут вполне рассылаться широковещательно, и обрабатываться синхронно. В альтернативу ООП очистки контролов начиная с рут-листов по схеме:

// ООП модель
void CMyApp:: ClearControls()
{
m_pMainDialog.ClearControls();
m_pTreeView.ClearControls();

m_pParent1.ClearControls();


m_pParentXXX.ClearControls();
и т.д.
}

А затем КАЖДЫЙ из листьев (родителей) перечисляет

void CParent1:: ClearControls()
{
m_pChield1. ClearControls();
m_pChield2. ClearControls();


m_pChieldXXX. ClearControls();
и т.д.
}

// Броадкаст рассылка
void CMyApp:: ClearControls()
{
Messanger.ClearControls();
}

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

С другой стороны сообщения типа UM_ERASE_DATABASEDATA или даже UM_READ часто не могут быть обработаны путём простого широковещания. В первом случае для транзакции может быть выполнен откат, во втором случае один из CWnd-объектов может читать данные, которые зависят от предварительно полученных по UM_READ другим CWnd-объектом. Например, закладка CPageXXX должна перерисоваться, или не перерисовываться только после получения или неполучения данных и отрисовки CTreeView.

Эти «негативные эффекты» броадкаста известны продвинутой публике и в теории и на практике. Посмотри паттерн Observer. Например, это

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

Бороться с негативом ясно, как. Есть следующие возможности:
А) для бродкаст-манагера «моделировать» асинхронную обработку подписчиками. Сложность решения ворзастает неимоверно.

Б) делать умных подписчисиков, запрашивающих стэйт и другое, пока даже не знаю, что…

В) дробить сообщения на более мелкие, например, UM_READ на UM_READ и UM_XXX_READ, что также не универсально и может перегружать логику приложения событиями

Г) делать что-нибудь нууууууууууу, совсем уж простое. Что я ПОКА и делаю, упорно сохраняя FillControls и DisplayControls в качестве виртуальных методов будущего «медиатора», получая пинки и подзатыльники. Как можно использовать FillControls и DisplayControls для группы подписчиков тоже понятно – если можно обработать мессагу бродкастом, то выполнить бродкаст из тела этих методов CMyMessanger:public CMessanger. Если необходим анализ очерёдности, или ещё чего (о чём можно знать только реализуя это в дочке CMessanger конкретного проекта) – то сделаем это. Короче говоря, FillControls и DisplayControls – это дополнительные посредники, вернее дополнительное средство анализа в посреднике (медиаторе). Если так не делать, то прямая дорога к п. А)Б)В), имхо.



*****************************
>>Теперь, собственно о вещах, которые я не понял.

>>Во первых, почему для тебя настолько важно использование виндового диспетчера >>сообщений. Зачем нужна цепочка SendMessage->GetMessage->DispatchMessage->(куча >>AfxXxxx методов различных MFC-шных классов)-> и в конце концов по >>MESSAGE_MAP-у к твоему обработчику?
A:

«цепочка SendMessage->GetMessage->» для меня не важна, как самостоятельная ценность. Она может оказаться полезной при организации обработки сообщений об изменении состояния системы, если используется широковещательная рассылка. Я оставил ЭТО и ТОЛЬКО ПОКА, до того как мы подведём черту топика, как некую альтернативу ООП способу оповещения посредников, про который ты и сам всё знаешь, и про который я хотел бы дать инфу отдельным постом (если модераторы не шрафанут меня за такие длинные постинги). Ты спросишь- а на кой? На других форумах часто кивали в эту сторону, мол, чё те надо – возьми SendMessage от API или от MFC и наслаждайся жизнью. Т.е. есть программеры, которые считают, что этого вообще достаточно. Поэтому давай ПОКА оставим SendMessage жизнь, как альтернативу для тех, кто это любит. Когда будем подводить черту в топике, возмём топор и всё лишнее поотрубаем, как Церрретттеллли ;))).

*****************************
>> Не проще ли действительно сделать theApp.Erase(), а он уже вызовет что ему надо дальше.

A:
Да конечно проще. Но, можно как ты, см. выше, а можно с «нарушением правил уличного движения ООП», броадкастом, см. выше врезку а-ля кода. Последнее содержит меньше программерского кода. А на счёт правильности и последствий пока не знаю.


*****************************
> TV->ClearTree();
> MAINPANEL->ClearControls();
> PAGE_GENERAL->ClearControls();
> PAGE2->ClearControls();
>>>Во-вторых. Большими буквами указаны макросы из "Мотивации"? ЗАЧЕМ????

Почему >>>они тебе так дороги???

A:
Да вовсе не дороги. Я время экономлю, ссылаясь на предыдущие фрагменты кода ;))).

*****************************
>>> Если можно обойтись обычными мембер-переменными класса, а в случае страниц lParam-ом из TCITEM-а? Как это делать я написал в ответе на мотивацию.

A:
Да, посмотрел. Если честно, скопировал в избранное. Чистенький код. Хотя, как ты понимаешь, у меня есть класс таба. Иначе как вообще МФК-ой пользоваться. А чужой код, тем более стильный никогда не помешает. Так что, спасибо.


*****************************
>>> Если порядок обработки указанного сообщения для нас
>>> не важен (что вначале – TV, или MAINPANEL? см. врезку
>Если сделать нормальную иерархию объектов, то рассылать нужно сверху-вниз слева->направо и тогда порядок всегда будет жестко задан - вот от него и отталкиваться >впоследвие.

A:
Я уже писал, что буду думать про иерархию. Важный вопрос. И не готов я что-либо возразить. Если б знал, то не обращался бы в форум. Живучесть иерархичных решений, которые моделируются ООП понятна. Меня мучает другой вопрос. Когда придёт время переделывать проект, поскольку какой-то баран-прикладник не до конца озвучил, что ему надо от задачи в постановочной части, - насколько «…тогда порядок всегда будет жестко задан …» будет гирями.

*****************************
>> выше), то можно просто широковещательно рассылать сообщение
>> UM_ERASE, например, при помощи функции SendMessage API, или

>Обоснуй необходимость SendMessage в конце то концов.
A:

Выше я уже обосновывал. В принципе – можно в топку. Но мне надо, пропостить завтра или сегодня «почти завершение топика» (там появится на свет медиатор-уродец), и тогда будет альтернатива. Вернее SendMessage будет альтернативой. Я хотел бы в конце топика посоветоваться с народом – оставить анахронизьм, или убить гада.

*****************************
>> 3) Может сложиться впечатление, что рассылка сообщений при
>> помощи SendMessage приближает стиль программирования к
>> парадигмам ООП, в отличие от использования FillControls,
>> DisplayControls. Это было бы ложным утверждением. И

>Глобальных обработчиков не должно быть ВООБЩЕ. Любой обработчик для >конкретного объекта должет быть функцией-членом класса ЭТОГО объекта. И все.

A:
Я уже писал об этом чуть выше. Нет у меня глобальных обработчиков. Есть глобальные дочки CMessager с паблик обработчиками. Можно вызывать их (для разрешения коллизий) или напрямую вызывать мембер-члены «команды» медиатора.

*****************************
>> 4) Я бы не противопоставлял возможность обработки
>> сообщений при помощи FillControls/DisplayControls
>> «альтернативному» методу доставки и анализа сообщений при
>> помощи SendMessage. Я бы комбинировал одно и другое. У
>> FillControls/DisplayControls есть одно преимущество – они
>> позволяют прозрачно контролировать ОБЩУЮ общую логику
>> событий приложения.

>Этого быть не должно. Или обоснуй необходимость или не задавай вопрос, если сам все решил :-)

A:
Я ответил выше про FillControls/DisplayControls – они нужны только для разрешения коллизий широковещательной рассылки, если таковые, по мнению программиста, могут появиться при обработке «потенциально коллизионных» сообщений.

*****************************
>>Если тебе близки такие вещи пиши лучше на Plain-C.
A:
Не буду. Мне не близок не один из языков программирования, которые я знаю. Мне близка моя девчёнка;))))

*****************************
>> BEGIN_MESSAGE_MAP(CPageGeneral, CDialog)
> >…
> >ON_MESSAGE(UM_NOTIFY, OnSendMessage)
> >ON_MESSAGE(UM_ ENABLE_CONTROLS,
> >OnEnableControlMessage)
> >ON_MESSAGE(UM_CLEAR_CONTROLS,
> >OnClearControlMessage)
> >ON_MESSAGE(UM_READ, OnReadControlMessage)
> >END_MESSAGE_MAP()

>Ну возврщаясь к уже заданному вопросу. А зачем ехать из москвы в подмосковье через >колыму?
>Если ты хочешь, чтоб была вызвана эта функция почему бы просто не вызвать ее. Зачем >тебе SendMessage?

A:
Я оставил SendMessage ПОКА ничего не сказал про методы около-медиатора, вернее специальный класс CMsgItem, который позволит обращаться с CMessanger, как с медиатором.
Убъём, обязательно убъём!!!
Другое, дело, что я хочу посоветоваться в конце, мож и про бродкаст забыть, а пользоваться только ООП?
<programming> Поиск 






Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach