Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.01.13;
Скачать: CL | DM;

Вниз

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

 
Ломброзо ©   (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;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.018 c
1-37752
gs
2003-12-30 03:34
2004.01.13
Подскажите, как добавить данные в свой EXE файл ?


14-37851
Думкин
2003-12-23 07:55
2004.01.13
С днем рождения! 23 декабря.


14-37914
BKGG
2003-12-20 21:40
2004.01.13
У моего друга задержка родов.


7-37967
Senti
2003-09-12 13:51
2004.01.13
Вопрос по управлению LPT портом.....


7-37948
Fants
2003-10-30 19:43
2004.01.13
CD-ROM