When writing Swing applications I find myself quite often in the Situation to write action handling code like this
(Why I do write this kind of code is a different albeit also interesting story):
public class Handler { Action doMyThing; public Handler() { doMyThing = new AbstractAction("doMyThing"){ public void actionPerformed(ActionEvent e) { doMyThing(); } }; } public void doMyThing(){ System.out.println("printlning is so my thing."); } }
No this looks ok at first sight. My IDE helps me creating that anonymous inner class and all. But as soon as there are
three or more actions on my presentation model things get really hard to read. C# introduced delegates for this kind of
problem, but what shall the poor Java programmer do?
The thing I tend to ask myself in such situations is, what would I like to write? What of the above code matters? what
is coincidental? So a naïve approach would look like this:
public class Handler { Action doMyThing; public void doMyThing(){ System.out.println("printlning is so my thing."); } }
I just slashed all the lines, that seem to be technicalities. And I like it. I still can exercise the doMyThing
method
in a unit test. And actually it doesn’t take that much to get the thing up and running. We have to do add in a constructor again.
But this one is only O(1) in length:
public class Handler { Action doMyThing; public Handler() { ActionReflector.reflectActions(this); } public void doMyThing(){ System.out.println("printlning is so my thing."); } }
I like this quite a lot. But how does it work. The reflector looks for all the fields of type Action. If they are null
it looks for a method with a matching name. Then it news up a new Action that calls this method and assigns it to the field.
If the method lookup fails an exception is thrown. So as long as the class is instantiated at least once in a unit test
– which is what one might hope for – the naming convention will actually be enforced.
Here is a a more complex example which illustrates the benefits of this approach.
public class Handler { Action doMyThing; Action doThisOtherThing; Action manualAction; public Handler() { manualAction = createManualAction(); ActionReflector.reflectActions(this); } public void doMyThing() { System.out.println("printlning is so my thing."); } public void doThisOtherThing() { System.out.println("printlning is also this other thing."); } private Action createManualAction() { return new AbstractAction("") { public void actionPerformed(ActionEvent e) { System.out.println("Doing a manual thing."); } }; } }
The manualAction field is assigned, before the reflector is run. This is quite handy if you just want to delegate to another
handler. So you combine the old and the new way easily.
If you forget to initialise it, the reflector will fail and tell you the method is missing.
Of course this approach can be extended. One thing I do is to have a second method, that indicates
whether the action is enabled. Generally speaking you could use this to implement multi-method interfaces by
having a naming convention for each method on the interface.
This niceness has to be paid with some infrastructure code, which is a bit ugly – mostly due to
all the declared exceptions in the java reflection.
In essence this gives you a delegate. It works very well for me. Even though you don’t have compile time security, it will
blow up as soon as you new your object up, if you get the spelling wrong.
Leave a Reply