Feb 2, 2009
Fun Friday: Simple java composite tricks
Welcome to the first fun friday installment, sometimes on a friday i’ll post one of those, and sometimes on a monday instead of friday, just like today.
Out first topic is a very simple trick using transparent proxies, looking nice when implementing Composites – you might have seen it called event sink depending on what kind of composite you’re making. We’ll use a list of instances and a proxy, both of a specified interface which can be any interface you want.
We’ll call a method on that proxy, and under the hood we’ll use that reified call to call the same method but on all the instances of our list, in a somewhat functional style. We’ll just loop over our elements inside the InvocationHandler used by the proxy and invoke the methods on each of them.
The interesting part here is that we can specify the container we’ll use to hold those elements (eg a specific collection – I’ve built an example with a LinkedList; a custom built collection – using Callables – where you can specify your way of creating the collection; or a special thread-safe collection), our own way of looping (from the end or from the beginning of the list; or depending on the type of listeners inside of it, say the ones which are not direct implementors will be called afterwards) and finally our own way of invoking the callback method on each instance (on the regular main thread; on a specified thread, say, EDT *wink*; or why not say that an exception thrown while invoking the callback method will invalidate the listener and remove it from the list of elements). This alllows versatile event handling code here too, and is only a couple hundred lines for the basic support.
Starting from a very simple interface.
public interface IComposite <T> { // you can return void // if you don't want method chaining IComposite<T> add (T t); IComposite<T> remove (T t); T delegate(); }
You can gradually build the different composite implementations we just talked about, and get code that looks like this pretty easily (just showing adding one element to the list and slighty reformated for easier reading here, changed some long methods names, etc – the full source is linked at the end of this post)
public class CompositeTest { // Totally random listener interface public static interface IListener { void callback (); } //Totally random listener interface too: // could have been MouseListener for instance public static interface ISwingListener extends EventListener { void callback (String event); } public static void main (String [] args) { IComposite<IListener> sink = Composites .createLinkedListComposite (IListener.class); sink.add (new IListener() { @Override public void callback () { System.out.println ("IListener callback ()"); } }); sink.delegate().callback(); IComposite<ISwingListener> sink2 = Composites .createEventComposite (ISwingListener.class); sink2.add (new ISwingListener() { @Override public void callback (String event) { System.out.println ("ISwingListener ('" + event + "') - on EDT: " + SwingUtilities.isEventDispatchThread ()); } }); sink2.delegate().callback ("Main thread test"); // And now with method chaining IComposite<ISwingListener> sink3 = Composites .createEDTComposite (ISwingListener.class) .add (new ISwingListener() { @Override public void callback (String event) { System.out.println ("ISwingListener ('" + event + "') - on EDT: " + SwingUtilities.isEventDispatchThread ()); } }); sink3.delegate().callback ("EDT dispatch test"); } }
It’s probably more instructive to do it yourself than using my code, since it’s very small, but here it is anyway (an Eclipse project). You could also imagine special composites that actually use what the callbacks return, like aggregating results or calculating mean min or max values.
See you next friday, monday, soon enough (: