views:

28

answers:

4

I have a listener class that accepts GUI change events in one method.

The incoming event objects have a superclass of a type of GUI Event, the behaviour should depend on the dynamic type of the incoming variable.

I wanted to do do lots of methods like:

handleGUIEvent(EventChangedX event)
handleGUIEvent(EventChangedY event)

I am using a single event listener and receiving objects of various types but the behaviour should be different for each. What would you do?

I do not want to use a switch statement as this would get unmaintainable.

A: 

You could put the knowledge of what to do in the various subclasses of GUI Event. This would decentralize the "controller" component in the standard model-view-controller paradigm, however.

Steve Emmerson
This won't work: Senders of events have no idea about the handlers, so they can't instantiate the correct subclass. Moreover, this would limit you to a single handler per event type.
Aaron Digulla
A: 

GUIEvent should provide an abstract method of the type

delegateEvent(EventListener el)

Each subclass should then implement this method, and call back on a particular method on EventListener. That way the subclasses of GUIEvent can determine what to call on EventListener, and the two object classes between them can determine what action to perform. This is known as double-dispatch. It avoids switch statements and the like.

Although I've drawn this out as EventListener calling on GUIEvent.delegateEvent and calling back on EventListener, there's no reason why there couldn't be a third class (say, EventReceiver). So the abstract method on GUIEvent would look like:

delegateEvent(EventReceiver er)

and EventReceiver would implement appropriate methods to be called by the GUIEvents.

Brian Agnew
The idea behind events is that they don't need to know anything about the handler. So this pattern doesn't work for anything but the most basic UIs.
Aaron Digulla
I don't see that at all. The above achieves polymorphism by putting behaviour in the events and their collaboration with other objects. It seems to me you're making an unstated assumption about these events.
Brian Agnew
This double-dispatch is also called Visitor pattern (GoF) but **it works when the type hierarchy** that we want to process polymorphically **is stable** and you don't have to add more types. If you add a type you have to add a "visit method" in the listener (then: lot of listeners -> problem).
helios
A: 

There are several options:

  • Create handler classes and register each handler in a map with the type (the class) of an event as the key. This way, you can do a single lookup in a map to get the handler.
  • Create a method which is called handle + the type of the event it handles (for example, handleMouseClick). Use reflection to find the correct handler.

The first approach is probably more simple (and needs much less try-catch).

Create a helper class for this. In the helper class, you can also add a lookup which uses getSuperClass() on the event class to handle inheritance of events.

Map<Class<?>, IHandler> map;

public IHandler handler (Event event)
{
    Class<?> current = event.getClass ();
    while (true)
    {
        handler = map.get (current);
        if (handler != null)
            return handler;

        if (current == null)
            break;

        current = current.getSuperclass ();
    }

    return new DummyHandler ();
}
Aaron Digulla
A: 

Here's what I have done so far and it seems to work well.

I have a number of GUI components that are incorporated in one large GUI but these components (and their events) ought to be useable outside of this frontend.

The large GUI uses the observer pattern and has a GUIController assigned to it. THe GUIController interface has a handleEventName method for every event.

handleEventX(RangeChange changed);
handleEventY(AlgorithmChange alg);

The subcomponents use instead actual events that propagate up to the large GUI who may handle the events via switch statements himself or pass them to the GUIController, who may in turn CALL for action on the GUI (message passing I think)

Improfane