Generic callback in Java

18,663

Solution 1

I'd recommend using Observer pattern since the Observer pattern is the gold standard in decoupling - the separation of objects that depend on each other.

But I'd recommend avoiding using the Java.util.Observable class if you are looking for a generic callback mechanism. Because Observable has a couple of weaknesses: it's not an interface, and forces you to use Object to represent events.

You can define your own event listener like this:

public class MyEvent extends EventObject {
    public MyEvent(Object source) {
        super(source);
    }
}

public interface MyEventListener {
    void handleEvent(EventObject event);
}

public class MyEventSource {
    private final List<MyEventListener> listeners;
    public MyEventSource() {
        listeners = new CopyOnWriteArrayList<MyEventListener>();
    }
    public void addMyEventListener(MyEventListener listener) {
        listeners.add(listener);
    }
    public void removeMyEventListener(MyEventListener listener) {
        listeners.remove(listener);
    }
    void fireEvent() {
        MyEvent event = new MyEvent(this);
        for (MyEventListener listener : listeners) {
            listener.handleEvent(event);
        }
    }
}

Solution 2

I would genericize the callback, based upon the type of Object passed. This is particularly useful for EventListeners listening for different classes of events. e.g.

public interface Callback<T> {
   public void callback(T t);
}

You may be able to use the type T as the key in a Map. Of course, if you want to differentiate between two callbacks that take the same argument, like a String, then you'd need something like your getID().

Here my old blog about using this for Event Listeners The interface Events.Listener corresponds to Callback<T> above. And Broadcasters uses a Map to keep track of multiple listeners based upon the class they accept as the argument.

Solution 3

looks like you want to implement the Observer pattern. In this url is a complete implementation for the observer pattern in Java. In your case the observer will be the callback.

Also If you need to implement something more complex, you will end up doing an event/notifier pattern. Take a look at this other pattern here.

Thanks, @leo.

Share:
18,663
PNS
Author by

PNS

Updated on June 04, 2022

Comments

  • PNS
    PNS almost 2 years

    What should be the preferable Java interface or similar pattern that could be used as a generic callback mechanism?

    For example it could be something like

    public interface GenericCallback
    {
        public String getID();
        public void callback(Object notification);
        // or public void callback(String id, Object notification);
    }
    

    The ID would be needed for cases of overriden hashCode() methods so that the callee identifies the caller.

    A pattern like the above is useful for objects that needs to report back to the class they were spawned from a condition (e.g., end of processing).

    In this scenario, the "parent" class would use the getID() method of each of these GenericCallback objects to keep a track of them in a Map<String, GenericCallable> and add or remove them according to the notification received.

    Also, how should such an interface be actually named?

    Many people seem to prefer the Java Observer pattern, but the Observable class defined there is not convenient, since it not an interface to circumvent single inheritance and it carries more functionality than actually needed in the above, simple scenario.

  • PNS
    PNS about 11 years
    The problem with the Observer pattern is that the Observable definition is a class, so due to single inheritance all classes that already subclass another class cannot become observable.
  • PNS
    PNS about 11 years
    I second what you say about Observable and creating a simpler version of that class as an interface (an approached suggested, for example, at stackoverflow.com/questions/11404034/java-interface-observab‌​le) also renders the Java Observer interface unusable, since that depends on Observable, too.
  • Brett
    Brett about 11 years
    I'd make a copy of listeners before trying to execute callback methods.
  • user949300
    user949300 about 11 years
    Even better than making a copy each time, use a CopyOnWriteArayList to hold the listeners.
  • Pavel Poley
    Pavel Poley about 5 years
    possible to apply generic callback with result and some cases with void type?