Elegant Event Handling in Java
Event handling is something very common, especially in desktop application. So how does you’re event handling code look like? Something like this?
Of course you don’t want to have this kind of code in every class. Therefore you create a special event-handling class. That class manages all registered events and can fire the event to all listeners.
But how do you do that when there are multiple event types? Then the types are represented by different interfaces with different method signatures. You really want to handle all these events with the same event-handler class. Let’s take a look at my solution. Here’s an example where I handle different events:
As you see I use the EventListeners for representing an event. To register events I just call the add-method on it. Now to the real cool part: To fire the event, I get the invoker and just call the method I want to. That method can by any method of the event-handler interface. That makes it very flexible; I can use this for any kind of event-handler interface! I haven’t seen a more elegant way to handle events in Java yet.
How is this implemented? The internally implements the usual add/remove and invoke-logic, but with a twist. It uses the generic argument for handling everything. For the invoke-part it creates a dynamic proxy object of the generic argument. That is the object which is returned by the invoker()-method. When you call any method on that object, it will delegate that invoke to all listeners. (Yes, for the .NET guys, that somewhat a reimplementation of a multi-cast delegate).
For my implementation I just used a Java proxy instance. Of course the implementation adds overhead to the call and only works with interfaces. For a more advanced implementation you could use a code generator library. That probably would speed up things and also allow classes as event-handlers.
That’s it. I handle my event this way in Java. If you found an event more elegant way, let me know.
P.S. I’m wondering if I should start a small Java library which contains all these kinds of small tricks I’m posting here. Hmm…
- LINQPad db4o Driver: Feature Overview
- Detectives in Trouble
Yes, that’s very elegant. I was implementing some Java class, when I went “hey, I need to handle events”. I know how to do this in Delphi and .NET/C#, and I know how to use Swing events (even if I don’t really like their approach).
So I’ve looked into JButton: http://www.docjar.com/html/api/javax/swing/JButton.java.html searching for “actionPerformed()” method, but no luck.
Then I went to AbstractButton: http://www.docjar.com/html/api/javax/swing/AbstractButton.java.html and found “fireActionPerformed()” – which looked pretty ugly.
I even went to EventListenerList: http://www.docjar.com/html/api/javax/swing/event/EventListenerList.java.html – to confirm my suspicion, that there is a mess in Java regarding events. And it is inherited from old, pre-generics, Swing design.
I knew there must have been some better way.
I’ve found: http://www.javaworld.com/javaworld/javaqa/2002-03/01-qa-0315-happyevent.html – funny, but not so useful.
Then this: http://castever.wordpress.com/2008/07/31/how-to-create-your-own-events-in-java/ – little better, and with synchronized methods (nice bonus).
This one looked promising: http://www.jillesvangurp.com/2005/10/26/late-to-generics/ – quite promising, but I kept on looking.
But your code is the best so far. I’m going to test it and will probably use it in my internal, little project.
Thanks a lot!
Thanks…
Just remind you that this adds some overhead for the dispatch with the proxy. However for most applications that should be a issue.
Also you maybe don’t like the ‘remove’ via disposable and prefer a remove method. Of course you can change that to your liking.
Solid way of handling events in Java! Did you ran into any problems were you’d like to handle events with return values?
I.e.:
public interface ComplexEventHandler {
boolean ohMyGod(String name,String otherName, int test);
}
return complexEvent.invoker().ohMyGod("complex","more complex",42);
This doesn’t seem to work…