Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Enforce strict type safety with generics

Create a simple event dispatcher using generics

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Event-driven design has been around for quite some time. Within Java, both AWT (Abstract Window Toolkit) and Swing are based on an event model. Java provides the classes EventQueue, AWTEvent, AWTEventMultiCaster, and EventListener in the java.awt package. However, because I wanted to use events generally and not merely in the context of graphical UI operations, I ended up writing a simple dispatcher of my own. In this article, I present the pre-generics version of this dispatcher and show how the introduction of generics improved the mechanism's usability.

I wanted an all-purpose dispatcher that would maintain listener lists for any type of event. The Swing tradition of writing many little methods to the pattern addXxxxListener(XxxxListener l); troubled me. To register a listener for an event, I wanted, as a client of my API, to be able to write this:

ThingChangedListener listener = new ThingChangedListener() { /* implement stuff here */ };
dispatcher.register(ThingChangedEvent.class, listener);


This way, the code interested in the event is completely decoupled from the code that generates the event. In the example above, I want to know when "ThingChanged" happens, but I don't care who makes it happen.

Similarly, to fire an event, I wanted to write this:

dispatcher.fire(new ThingChangedEvent());


Now I present the implementation of Dispatcher—first, the pre-generics version, then the generics version. It will be satisfying to observe that client code (such as the two examples above) will remain unaffected by the migration.

In the bad old days ...

Dispatcher used to look like this:

class Dispatcher {
    Map map;
    void register(Class eventClass, Object listener) { ... }
    void fire(Event event) { ... }
}


Notice that the register() method takes an Object as the second parameter. In other words, it knows nothing about the listener type. Dispatcher gets away with this because it expects Event objects to know how to dispatch themselves. Exactly how events dispatch themselves will become clearer soon.

The register() method adds its listener parameter to a list stored in a map keyed by the eventClass parameter, as follows:

void register(Class type, Object listener) {
    List list = (List)map.get(type);
    if (list == null) {
       list = new ArrayList();
       map.put(type, list);
    }
    list.add(listener);
}


The fire() method iterates through the list of registered listeners and asks Event to handle each listener by calling its dispatchTo() method. This way, Dispatcher and the listener types are completely decoupled; Dispatcher requires no knowledge about the listener interface. fire() looks like this:

void fire(Event event) {
    List list = (List)map.get(event.getClass());
    if (list == null) {
       return;
    }
    for (Iterator i = list.iterator(); i.hasNext();) {
       event.dispatchTo(i.next());
    }
}


Here is the Event interface:

interface Event {
    void dispatchTo(Object listener);
}


This interface is somewhat inspired by java.awt.ActiveEvent. It differs in that the dispatch method takes a parameter, the listener to which Event should dispatch itself. This parameter's type is Object; in other words, it lacks type information. An Event implementation casts its listener parameter to the desired type and then calls whatever method it wants on its listener. Here's an example:

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comment
Login
Forgot your account info?
Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Archived Discussions (Read only)
Subject
. Forum migration complete By AthenAdministrator
. Forum migration update By AthenAdministrator
. Enforce type safety By JavaWorld
. How to By Toine
. Bad example of generics By Andrej N
. Why? By Igor Poltosi
. Interfaces By Mark Lyttle
Resources