Я недавно реализовал нечто похожее на то, что вы описываете. Я начал с создания класса EventManager, в котором есть методы «Опубликовать» и «Подписаться». Когда система запускается, она сканирует все загруженные сборки (библиотеки) на предмет классов, которые реализуют интерфейс IEventListener:
/// <summary>
/// A class that intends to listen for specific events to be published by an
/// event manager.
/// <see cref="EventManager"/>
/// </summary>
public interface IEventListener
{
/// <summary>
/// Subscribes to the event types that this listener wishes to listen for.
/// </summary>
/// <param name="eventManager"></param>
void RegisterSubscriptions(EventManager eventManager);
}
... и вызывает метод RegisterSubscription для каждого из них. (Существует только один экземпляр EventManager, который используется повсеместно; я использую внедрение зависимостей, чтобы связать его как одноэлементный экземпляр.)
RegisterSubscription просто вызывает метод Subscribe для каждого типа события и обработчика, которые данный класс предназначен для обработки. (Я использую .NET, поэтому с событиями и обработчиками немного проще работать, но вы можете сделать то же самое в Java, используя анонимные подклассы.)
Типичным событием может быть что-то вроде RoomEntered, а аргументы, связанные с этим событием, включают идентификатор комнаты и, возможно, некоторые другие свойства комнаты. Движок игры публикует это событие, когда пользователь входит в комнату, предоставляя соответствующие аргументы события для этой комнаты, и класс EventManager отвечает за вызов каждого обработчика, подписавшегося на этот тип события. Одним из обработчиков этого события может быть «HandleEnterRoomWithMonsters», который проверяет, есть ли в комнате монстры, и выполняет соответствующее действие.
Имеет ли это смысл в целом? Есть ли у вас какие-либо вопросы об этом подходе?