如果每个事件都有特定的侦听器接口。每个事件都能够发出侦听器调用本身。然后,调度程序的角色是标识目标侦听器并触发其上的事件通知。
例如,泛型事件定义可以是:
public interface GameEvent<L> {
public void notify( final L listener);
}
如果您的碰撞观察器是:
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约束(每个事件选择自己的消息),
- 演化(不同事件和/或侦听器之间没有依赖关系),
- 调度程序是一个通用的黑匣子,
- 消费者和生产者不需要相互了解。