views:

74

answers:

3

Very typically I have a situation where a given object will need to have many listeners. For instance, I might have

class Elephant {
  public void addListener( ElephantListener listener ) { ... }
}

but I'll have many such situations. That is, I'll also have a Tiger object that'll have TigerListeners. Now, TigerListeners and ElephantListeners are quite different:

interface TigerListener {
  void listenForGrowl( Growl qrowl );
  void listenForMeow( Meow meow );
}

while

interface ElephantListener {
  void listenForStomp( String location, double intensity );
}

I find that I always have to keep re-implementing the broadcasting mechanism in each animal class, and the implementation is always the same. Is there a preferred pattern?

+2  A: 

Instead of each Listener having specific methods for every event type you can send it, change the interface to accept a generic Event class. You can then subclass Event to specific subtypes if you need, or have it contain state such as double intensity.

TigerListener and ElephentListener then become

interface TigerListener {
    void listen(Event event);
}

In fact, you can then further refactor this interface into a plain Listener:

interface Listener {
    void listen(Event event);
}

Your Listener implementations can then contain the logic that they need for the specific events they care about

class TigerListener implements Listener {
    @Overrides
    void listen(Event event) {
        if (event instanceof GrowlEvent) {
            //handle growl...
        }
        else if (event instance of MeowEvent) {
            //handle meow
        }
        //we don't care about any other types of Events
    }
}

class ElephentListener {
    @Overrides
    void listen(Event event) {
        if (event instanceof StompEvent) {
            StompEvent stomp = (StompEvent) event;
            if ("north".equals(stomp.getLocation()) && stomp.getDistance() > 10) { 
                ... 
            }
        }
    }
}

The key relationship between the subscriber and the publisher is that the publisher can send events to the subscribers, it isn't necessarily that it can send it certain types of events - this type of refactoring pushes that logic from the interface down into the specific implementations.

matt b
I guess my question was really about which implementation is preferred. The broadcasting mechanism is re-implemented three times in my code (not that much in the scheme of things), while your version requires a whole new object hierarchy and instanceof statements. There are advantages and disadvantages, but how do I choose the right method for the situation at hand?
Jake
Also, there is a very valid point about loss of readability when the number of Event types is large.
Jake
Well you could replace `instanceof` with use of generics if you really care about that, or some other OO solution. I don't see that as a problem. I interpreted your question as not being pleased with the repeated definition of listener interfaces in your code, this is an approach to deal with that. And I don't really see your point about losing readability - I think that separating out the concept of `Event`s from the listener interface removes the need to duplicate definitions of what a `Listener` is.
matt b
Personally I would chose defining one interface and one method to deal with (`listen(Event)`) rather than re-defining a `listenFoo()` method a bunch of different ways.
matt b
+1  A: 

I think you're doing it correct, since your interfaces have semantic value and express what they are listening to (e.g. growls and meows instead of stomps). With a generic approach, you may be able to reuse the broadcasting code, but you may lose the readability.

For example, there is the java.beans.PropertyChangeSupport which is a utility for implementing Oberservers listening for value changes. It does the broadcasting, but you still need to implement the method in your domain class and delegate to the PropertyChangeSupport object. The callback methods are meaningless by themselves, and the events broadcasted are String-based:

public interface PropertyChangeListener extends java.util.EventListener {
     void propertyChange(PropertyChangeEvent evt);
}

Another one is java.util.Observable which provides the broadcasting mechanism, but it's also not the best thing imho.

I like ElephantListener.onStomp()

mhaller
The semantic value, while a valid argument, creates tight coupling (and change risk). Good eye, but I can't agree.
Justin
+1  A: 

A different options is the Whiteboard Pattern. This disconnects the publisher and subscriber from each other, and neither will contain any broadcasting code. They both simply use a messaging mechanism for pub/sub and neither has any direct connection to the other.

This is a common model for messaging in an OSGi platform.

Robin