Форум: "Потрепаться";
Текущий архив: 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