Simple java message dispatching system

前端 未结 3 1856
清歌不尽
清歌不尽 2021-01-29 20:35

I\'m working on a little Java game in which all sorts of events can happen. There are at least a couple of dozen basic events that various event handlers may be interested in.

3条回答
  •  北荒
    北荒 (楼主)
    2021-01-29 21:03

    If there is a specific listener interface for each event. Each event is able to issue listeners calls itself. Then, the role of the dispatcher is to identify target listeners and to trigger the event notification on them.

    For example, a generic event definition can be:

    public interface GameEvent {
    
       public void notify( final L listener);
    }
    

    If your CollisionListener is:

    public interface CollisionListener {
    
        public void spaceshipCollidedWithMeteor( Spaceship spaceship, Meteor meteor );
    
    }
    

    Then, the corresponding event can be:

    public final class Collision implements GameEvent {
    
       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 );
       }
    
    }
    

    You can imagine a dispatcher which is able to propagate this event on the target listeners like in the following scenario (Events is the dispatcher class):

    // 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  ) );
    

    In this scenario, the dispatcher did not require any knowledge on events and listeners. It triggers an individual event notification to each listener, using only the GameEvent interface. Each event/listener pair chooses it's own dialog modalities (they can exchange many messages if they want).

    A typical implementation of a such dispatcher should be something like:

    public final class Events {
    
       /** mapping of class events to active listeners **/
       private final HashMap map = new HashMap( 10 );
    
       /** Add a listener to an event class **/
       public  void listen( Class> evtClass, L listener) {
          final ArrayList listeners = listenersOf( evtClass );
          synchronized( listeners ) {
             if ( !listeners.contains( listener ) ) {
                listeners.add( listener );
             }
          }
       }
    
        /** Stop sending an event class to a given listener **/
        public  void mute( Class> evtClass, L listener) {
          final ArrayList listeners = listenersOf( evtClass );
          synchronized( listeners ) {
             listeners.remove( listener );
          }
       }
    
       /** Gets listeners for a given event class **/
       private  ArrayList listenersOf(Class> evtClass) {
          synchronized ( map ) {
             @SuppressWarnings("unchecked")
             final ArrayList existing = map.get( evtClass );
             if (existing != null) {
                return existing;
             }
    
             final ArrayList emptyList = new ArrayList(5);
             map.put(evtClass, emptyList);
             return emptyList;
          }
       }
    
    
       /** Notify a new event to registered listeners of this event class **/
       public  void notify( final GameEvent evt) {
          @SuppressWarnings("unchecked")
          Class> evtClass = (Class>) evt.getClass();
    
          for ( L listener : listenersOf(  evtClass ) ) {
             evt.notify(listener);
          }
       }
    
    }   
    

    I suppose its fulfills your requirements:

    • very light,
    • fast,
    • no casts (at usage),
    • Every thing is checked at compile time (no possible mistake),
    • No API constraints on listeners (each event choose it's own messages),
    • Evolutive (no dependencies between different events and/or listeners),
    • The dispatcher is a generic black box,
    • Consumers and producers don't need to know each other.

提交回复
热议问题