Спасибо всем за ответы.
Odyssey писал(а):Если иерархия наследования менеджеров не занята, то можно объявить их базовый
тип в модуле диспетчера, что-то типа TSubscriber, о котором диспетчер знает.
...
Если менеджеры уже наследуются от чего-то определённого, можно использовать интерфейсы.
У менеджеров есть базовый класс "Абстрактный менеджер". Возможно, конечно,
делать через иерархию. Но тут есть один минус.
Как таковых "менеджеров", наследуемых от данного класса у меня всего три.
Каждый менеджер работает с сущностью (например клиент).
Но есть ещё, например, окно, где могут изменяться справочники. И т.п.
Реально оно не является менеджером. Но, при изменении справочников другим пользователем,
если окно открыто, его тоже надо обновлять, я так думаю...
Что касается механизма сообщений -- тут мне сложно что-то сказать.
Я видел не очень много кода, но почему-то нигде кроме GUI-библиотек (LCL, fpGUI)
не использовались message.
...
Похоже что "из коробки" нет ни очереди сообщений, ни broadcast-рассылки,
для этого используются возможности ОС (SendMessage/PostMessage под Win32).
Просто я видел в коде какие-то сообщения не WM_*.
Меня это навело на мысль, что должен быть какой-то свой кроссплатформенный
механизм сообщений. Или "оболочка" для них над средствами конкретной ОС.
Если использовать её где попало без особой необходимости,
в конце концов объекты на каждый чих будут тревожить всю систему.
Да, об этом я не подумал. Получается, что широковещательная рассылка точно не подходит.
Timid писал(а):При подписке вы передаете в метод имя таблицы и ссылку на
обработчик, метод возвращает вам индекс. Его сохраняете в своей форме-окне.
Да, идея с занесением имени таблицы хорошая. Буду думать, как сделать.
Мне бы это позволило отделить "слой данных" от диспетчера.
И о назначении таблиц, тогда знали бы только менеджеры.
Сейчас я сделал достаточно тупо: есть объект, который, обрабатывая событие
"Диспетчера обновления таблиц", по имени таблицы выбирает действие:
- Код: Выделить всё
// Тип события, создаваемого, при обновлении сущности.
TEntityUpdateEvent = procedure(const entity_id: TTableRecordID;
const update_type: TUpdateType);
// Тип события, создаваемого, при обновлении справочника.
TInfoUpdateEvent = procedure(const table_name: string;
const update_type: TUpdateType);
// Диспетчер обновлений.
TDBUpdateDispatcher = class(TObject)
private
FTRDispatcher: TTablesRefreshDispatcher;
protected
public
procedure Refresh();
property Active: boolean read GetActive write SetActive;
public
property OnClientUpdate: TEntityUpdateEvent read FOnClientUpdate
write FOnClientUpdate;
property OnCarUpdate: TEntityUpdateEvent read FOnCarUpdate
write FOnCarUpdate;
property OnContractUpdate: TEntityUpdateEvent read FOnContractUpdate
write FOnContractUpdate;
property OnUserUpdate: TEntityUpdateEvent read FOnUserUpdate
write FOnUserUpdate;
property OnInfosUpdate: TInfoUpdateEvent read FOnInfosUpdate
write FOnInfosUpdate;
end;
В принципе, гораздо лучше сделать, чтобы менеджеры сами регистрировали обработчик события.
Сама схемка оповещения достаточно проста:
1.) При обновлении таблицы, триггер на сервере пишет имя таблицы, ключ, время и
тип обновления (вставка/изменение/удаление) в таблицу change_log.
2.) Объект "Диспетчер обновления таблиц" читает эту таблицу раз в n секунд.
3.) Производит обработку, в результате которой получается список обновлённых таблиц.
Т.е. выделяется последняя по времени запись с данным ID для полученной
таблицы и её время сравнивается с сохранённым.
4.) Во время второго прохода, создаются события для каждой обновлённой записи.
5.) Диспетчер обновления создаёт события по типам таблиц.
Для справочников записи не учитываются, а событие создаётся для всей таблицы.
6.) Менеджеры обрабатывают события, подходящие для них.
7.) Менеджеры оповещают остальные окна, которые требуют обновления.
- Код: Выделить всё
// Тип события, создаваемого, при обновлении таблицы.
TTableUpdateEvent = procedure(const table_name: string;
const update_type: TUpdateType; const record_id: TTableRecordID);
// Диспетчер обновления таблиц.
TTablesRefreshDispatcher = class(TObject)
public
procedure ReadSettings();
procedure Refresh();
public
property Active: boolean read GetActive write SetActive;
property OnUpdate: TTableUpdateEvent read FOnUpdate write FOnUpdate;
end;
Climber писал(а):Буквально в прошлый четверг делал для себя такую штуку (шаблон Publisher - Subscriber) называется.
О том я и думал, вначале.
Но сейчас решил немного по-другому, поскольку:
1.) У меня иерархия вызовов менеджеров.
2.) Главное окно - одновременно менеджер.
Главное окно обрабатывает события.
При необходимости, оповещает другие менеджеры/окна.
Если менеджер вызывает подчинённый менеджер, то главный оповещает подчинённого.
Добавлено спустя 1 минуту 55 секунд:Конечно, может, с этим тоже проблемы будут...