Если для каждого события есть определенный интерфейс слушателя. Каждое событие может выдавать слушателям вызовы самостоятельно. Затем роль диспетчера состоит в том, чтобы идентифицировать целевых слушателей и инициировать на них уведомление о событии.
Например, общее определение события может быть:
public interface GameEvent<L> {
public void notify( final L listener);
}
Если ваш CollisionListener:
public interface CollisionListener {
public void spaceshipCollidedWithMeteor( Spaceship spaceship, Meteor meteor );
}
Тогда соответствующее событие может быть:
public final class Collision implements GameEvent<CollisionListener> {
private final Spaceship ship;
private final Meteor meteor;
public Collision( final Spaceship aShip, final Meteor aMeteor ) {
this.ship = aShip;
this.meteor = aMeteor;
}
public void notify( final CollisionListener listener) {
listener.spaceshipCollidedWithMeteor( ship, meteor );
}
}
Вы можете представить диспетчера, который может распространить это событие на целевых слушателей, как в следующем сценарии (Events - это класс диспетчера):
// A unique dispatcher
final static Events events = new Events();
// Somewhere, an observer is interested by collision events
CollisionListener observer = ...
events.listen( Collision.class, observer );
// there is some moving parts
Spaceship aShip = ...
Meteor aMeteor = ...
// Later they collide => a collision event is notified trough the dispatcher
events.notify( new Collision( aShip, aMeteor ) );
В этом случае диспетчеру не потребовалось никаких знаний о событиях и слушателях. Это вызывает отдельное уведомление о событии для каждого слушателя, используя только интерфейс GameEvent. Каждая пара событие / слушатель выбирает свои собственные условия диалога (они могут обмениваться многими сообщениями, если хотят).
Типичная реализация такого диспетчера должна выглядеть примерно так:
public final class Events {
/** mapping of class events to active listeners **/
private final HashMap<Class,ArrayList> map = new HashMap<Class,ArrayList >( 10 );
/** Add a listener to an event class **/
public <L> void listen( Class<? extends GameEvent<L>> evtClass, L listener) {
final ArrayList<L> listeners = listenersOf( evtClass );
synchronized( listeners ) {
if ( !listeners.contains( listener ) ) {
listeners.add( listener );
}
}
}
/** Stop sending an event class to a given listener **/
public <L> void mute( Class<? extends GameEvent<L>> evtClass, L listener) {
final ArrayList<L> listeners = listenersOf( evtClass );
synchronized( listeners ) {
listeners.remove( listener );
}
}
/** Gets listeners for a given event class **/
private <L> ArrayList<L> listenersOf(Class<? extends GameEvent<L>> evtClass) {
synchronized ( map ) {
@SuppressWarnings("unchecked")
final ArrayList<L> existing = map.get( evtClass );
if (existing != null) {
return existing;
}
final ArrayList<L> emptyList = new ArrayList<L>(5);
map.put(evtClass, emptyList);
return emptyList;
}
}
/** Notify a new event to registered listeners of this event class **/
public <L> void notify( final GameEvent<L> evt) {
@SuppressWarnings("unchecked")
Class<GameEvent<L>> evtClass = (Class<GameEvent<L>>) evt.getClass();
for ( L listener : listenersOf( evtClass ) ) {
evt.notify(listener);
}
}
}
Я полагаю, он удовлетворяет вашим требованиям:
- очень легкий,
- быстро
- без кастов (при использовании),
- Все проверяется при компиляции
время (без возможных ошибок),
- Нет ограничений API для слушателей (каждое событие
выбирай свои сообщения)
- Evolutive (нет зависимости между
разные события и / или слушатели),
- Диспетчер - черный
коробка
- Потребителям и производителям не нужно
знать друг друга.