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

Вниз

Ваши соображения по архитектуре?   Найти похожие ветки 

 
Ломброзо   (2003-12-20 17:54) [0]

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

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

Как грамотно подвязаться к этим событиям при наличии изменяющегося числа клиентов? Аналога делегатов .NET в Builder нет, потому мыслю сделать так: у сервера смастерить контейнер указателей на экземпляры клиентов (псевдокод)
class FSOManager
private FClients: TCollection
end;

procedure FSOManager.Advise(Client: TObject)
begin
FClients.Add(Client)
end;

TCLient1 = class (TTreeFrame)
public
procedure Update;
end;
TClient2 = class(TListFrame)
procedure Update;
end;

, а при возникновении события пробегаться по всем клиентам и вызывать MethodAdress("Update").

Всё бы хорошо, но вот использование MethodAddress смущает. Существуют ли решения покрасивше?


 
Игорь Шевченко   (2003-12-20 18:04) [1]

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


 
Nikolay M.   (2003-12-20 18:08) [2]


> Существуют ли решения покрасивше?

COM? Правда, я не совсем въехал в суть задачи, но, имхо, ты просто пытаешься руками реализовать IDispatch.Invoke.


 
Ломброзо   (2003-12-20 18:12) [3]

Я об этом думал.
Пишу в Builder. Код

struct IEvent
{
void Update() = 0;
};

class TFraTreeFolders : public TFrame, public IX
{
...
}


Выдаёт ошибку
Declaration if TFraTreeFolders is missing or incorrect.
Это какой-то ужасный глюк Билдера.

Тэкс, а вот - если в сделать сделать не контейнер объектов-клиентов, а контейнер указателей на их метод Update?


 
Ломброзо   (2003-12-20 18:14) [4]

т.е.
class TFraTreeFolders : public TFrame, public IEvent


 
Vuk   (2003-12-20 18:21) [5]

Хм... В CB вроде было запрещено множественное наследование для VCL классов...


 
Ломброзо   (2003-12-20 18:25) [6]

Vuk © (20.12.03 18:21) [5]
Точно? не знал. Спасибо.
Странно. Я наследую не от класса, а от интерфейса. Пробовал наследовать сразу от TFrame и от IUnknown, и в Delphi такой фокус прокатывает, а в CBuilder ругань выдаёт IDE (не компилятор)


 
nikkie   (2003-12-20 18:28) [7]

>ты просто пытаешься руками реализовать IDispatch.Invoke
ну не IDispatch.Invoke, а IConnectionPoint.Advise...

а действительно, почему не COM?


 
Ломброзо   (2003-12-20 18:37) [8]

> nikkie © (20.12.03 18:28) [7]
Если честно, то просто лень, потому что громоздко. В общем-то в ATL метод Fire_XXX делает примерно то же самое, что и MethodAdress - вызывает Invoke с нужным DISPID у каждого клиента.


 
Vuk   (2003-12-20 18:43) [9]

to Ломброзо:
>Точно?
Давно я билдера в глаза не видел. Сейчас поглядел по yandex, все именно так, множественное наследование для VCL и вообще Delphi-классов (те, которые наследники TObject из Delphi) запрещено.

Если хотите в Вашем классе реализацию интерфейсов, то проще сделать для фреймов общего предка, написанного на Delphi. По идее в .pas реализацию интерфейса провернуть можно... Хотя, может в CB для реализации интерфейсов в стиле Delphi есть какие нибудь средства(я просто не в курсе)?

Все дело в том, что в delphi реализация интерфейса - это совсем не то же самое, что множественное наследование в C++.

to nikkie:
>а действительно, почему не COM?
Ну может неудобно по каким-то причинам его использовать...


 
Ломброзо   (2003-12-20 18:56) [10]

nikkie © (20.12.03 18:28)
Vuk © (20.12.03 18:43)

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


 
kaif   (2003-12-20 18:56) [11]

А если подумать еще в направлении хуков? Глобальная переменная-указатель на процедуру. Любой экземляр при создании себя подменяет значение указателя на свою процедуру (обработчик события), которая в своем теле вызывает еще и процедуру, которая была подменена. Так они будут вызывать друг друга и список сканировать не надо. Важно аккуратно удалять эти хуки при destroy-е объектов. В качестве глобальной переменной можно использовать (если постараться) даже не указатель на процедуру, а указатель на метод.
Это не решение. Это просто еще одно направление для размышления...


 
Ломброзо   (2003-12-20 19:00) [12]

М-дя. Вложенные классы тоже не поддерживаются :-)


 
Ломброзо   (2003-12-20 19:02) [13]

kaif © (20.12.03 18:56) [11]
Тоже можно. Что-то навроде очереди сообщений, да?


 
kaif   (2003-12-20 19:11) [14]

2 Ломброзо © (20.12.03 19:02) [13]
Мне все же кажется, что если ты сможешь задействовать COM - лучше использовать COM.
Еще есть вариант (так как это фреймы) создать специальный компонент типа TMyGlobalEvents и кидать его на эти фреймы руками или создавать runtime (если фреймы создаются runtime). Этот компонент в методе класса Create будет иметь регистрацию в глобальном списке указателей на все такие экземляры, который можно сканировать (как ты и собирался вначале). Это очень дубовое решение. Я бы так и сделал, так как я не программист, а скорее, продвинутый юзер. К тому же тогда у меня была бы простая возможность добавлять новые типы событий в этот компонент, просто развивая текст его класса (в одном месте).


 
kaif   (2003-12-20 19:14) [15]

Примерно так реализован класс TApplicationEvents с палитры Additional.


 
kaif   (2003-12-20 19:26) [16]

Кстати (может пригодится?), у фреймов вроде нет события OnCreate (как у формы). Но я выходил из затруднения, переопределяя виртуальный конструктор Create(AOwner: TComponent) прямо в модуле, где создан этот фрейм. Ведь все конкретные фреймы это наследники TFrame. Просто они проектируются визуально. Но туда можно добавить переопределения виртуальных методов и это работает в runtime. А вообще с фреймами много глюков связано. Некоторые кривые компоненты на фреймах плохо себя ведут.


 
Vuk   (2003-12-20 19:36) [17]

to kaif:
>я выходил из затруднения, переопределяя виртуальный конструктор
Я обычно AfterConstruction перекрываю. Это именно то место, откуда у форм OnCreate вызывается.

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


 
kaif   (2003-12-20 19:47) [18]

2 Vuk © (20.12.03 19:36) [17]
Спасибо. Это хорошая информация.


 
Ломброзо   (2003-12-20 20:22) [19]

> kaif © (20.12.03 19:26) [16]
В С++ конструктор не является виртуальным, поэтому можно сильно огрести Access Violation при работе с виртуальными методами в конструкторах (и, как разновидностью, с событиями) - когда объекта ещё нет, а его метод уже вызван.
* * *
Уф, всем спасибо, но всё-таки ни COM, ни MethodAddress я решил не использовать, сделал все на темплейтных классах.


 
nikkie   (2003-12-20 20:53) [20]

надо же... какая оказывается убогая штука CB ;)


 
Ломброзо   (2003-12-20 21:22) [21]

Точно. Вот кто во всём виноват! Я уж было грешным делом на свои руки подумал.



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

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

Наверх




Память: 0.5 MB
Время: 0.008 c
3-37524
OlegM
2003-12-16 10:00
2004.01.13
Добавить изображение в Blob поле


14-37869
DCoder
2003-12-22 17:14
2004.01.13
Порекомендуйте почтовый сервер


14-37872
strupik
2003-10-10 17:47
2004.01.13
Компьютерные ИГРЫ и их будущее..


1-37605
NneRreaLl
2003-12-29 01:07
2004.01.13
Передать результат


8-37810
begemot
2003-09-10 21:40
2004.01.13
CDROM занят?





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский