Чтобы иметь возможность проверить, реализует ли экземпляр данный интерфейс, этот интерфейс должен иметь определенный GUID. Итак, добавьте guid в свой интерфейс (вам также понадобится этот guid в константе или переменной, чтобы вы могли ссылаться на него позже в коде):
const
IID_Handle: TGUID = '{0D3599E1-2E1B-4BC1-ABC9-B654817EC6F1}';
type
IHandle<TMessage> = interface
['{0D3599E1-2E1B-4BC1-ABC9-B654817EC6F1}']
procedure Handle(AMessage: TMessage);
end;
(Вы не должны использовать мой guid, это просто пример... нажмите ctrl+shift+G, чтобы сгенерировать новый guid в IDE).
Затем проверьте, поддерживает ли зарегистрированный подписчик этот интерфейс:
// LTarget:= LReference as IHandle; // <-- Wish this would work
if Supports(LReference, IID_Handle, LTarget) then
LTarget.Handle(AMessage);
Однако при этом не учитывается общая часть интерфейса, проверяется только GUID.
Таким образом, вам понадобится дополнительная логика, чтобы проверить, действительно ли цель поддерживает тип сообщения.
Кроме того, поскольку вы имеете дело с классами, которые будут реализовывать интерфейс и, следовательно, должны быть производными от TInterfacedObject (или совместимого интерфейса с этим классом), вы должны сохранить все ссылки на созданный объект в переменных интерфейса, таким образом, изменив список подписчиков с ссылка на TObjects' на один из IInterfaces'. И для этого тоже есть специальный класс:
FSubscribers: TInterfaceList;
Конечно, вам также придется изменить подпись для функций подписки/отписки:
procedure Subscribe(AInstance: IInterface);
procedure Unsubscribe(AInstance: IInterface);
Я думаю, что лучшим способом было бы убрать общий интерфейс IHandle. Таким образом, вы можете обеспечить, чтобы все подписчики реализовали базовый интерфейс IHandler, изменив подпись подписки/отмены подписки, чтобы использовать IHandler вместо IInterface.
Затем IHandler может содержать функциональные возможности, необходимые для определения того, поддерживает ли подписчик данный тип сообщения или нет.
Это будет оставлено читателю в качестве упражнения. Вы можете начать с моего небольшого тестового приложения (D2010), которое можно загрузить с My Тестовое приложение.
Н.Б. Тестовое приложение исследует возможность использования дженериков в интерфейсе и, скорее всего, вылетит при публикации событий. Используйте отладчик для одного шага, чтобы увидеть, что происходит. У меня не происходит сбой при публикации целого числа 0, что, кажется, работает. Причина в том, что обработчики Int и String будут вызываться независимо от типа ввода для публикации (как обсуждалось ранее).
10.09.2010