Ответ 1
Если для каждого события есть специальный интерфейс слушателя. Каждое событие может выдавать сами вызовы слушателей. Затем роль диспетчера состоит в том, чтобы идентифицировать целевых слушателей и инициировать уведомление о событиях на них.
Например, определение общего события может быть:
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 );
}
}
Вы можете представить диспетчера, который может распространять это событие на целевых слушателей, например, в следующем сценарии (События - это класс диспетчера):
// 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( ship, meteor ) );
В этом случае диспетчер не требовал каких-либо знаний о событиях и слушателях. Он запускает индивидуальное уведомление о событии для каждого слушателя, используя только интерфейс 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 (без зависимостей между различные события и/или слушатели),
- Диспетчер - это общий черный коробка,
- Потребителям и производителям не нужно знают друг друга.