MattHicks.com

Programming on the Edge

Java Delegates in xjava

Published by Matt Hicks under , , , , , , on Tuesday, July 07, 2009
I posted over a year ago about Delegates in Java, and since I kicked off an exploration of the functionality I'm providing in my xjava framework with my previous post I thought I would continue with my newest iteration of the Delegates concept as utilized in xjava.

Until you use a language like Scala or Flex that has full delegate support, you can't really appreciate what it is you're missing. As Java programmers we take it for granted that if we need to do some "work" we usually have to create a Runnable implementation that implements the run() method to do the work we need to do:

Runnable r = new Runnable() {
public void run() {
... do work ...
}
};
passWorkOff(r);

However, in other languages that support Delegates you can pass methods/functions as parameters to methods/functions to simplify this process greatly. Consider the alternative:

public void someMethod() {
passWorkOff(this.doWork);
}

public void doWork() {
... do work ...
}

This minimizes the amount of custom/anonymous classes you must create in order to pass a unit of work off.

Unfortunately in Java this functionality is not (yet) supported. Many people have created work-arounds, generally with Java Reflection, but none can support the elegance of the native delegate support other languages have.

I may be known for my rants, but I won't leave you hanging here with a negative thought of Java, I love the language too much to do that. Besides, I have a framework to promote, so lets get to it. :)

In xjava there is a simple interface Delegate:

public interface Delegate {
public Object invoke(Object ... args) throws Exception;
}

The invoke method takes a varargs of Objects and returns an Object. It's pretty straight and simple, but the out-working of the implementations are what add significant power to this concept.

There are several different implementations, but by far the most used and most powerful is MethodDelegate. In our above example of using delegates in other languages to pass a function, this imlementation fulfills that role with the following call:

MethodDelegate delegate = new MethodDelegate(this, "doWork");
passWorkOff(delegate);

This presumes that the passWorkOff method takes a Delegate as a parameter. Like I said, this isn't as good as native support, but it's pretty simple and although you lose the ability to have compile-time checking that you're referencing a valid method, it will throw an exception at runtime if the method referenced is unable to be found.

MethodDelegate has some extremely powerful features that have been added to make it even more powerful though. One such feature is the ability to mix and match when arguments are applied to the method being invoked. Say you have the following method you want to invoke:

public void doSomething(String name, String address) {
....
}

Now, at creation time of the Delegate you know what "name" is, but in the place you wish to use the delegate you only know the address. See the following:

public void someMethod() {
Delegate d = MethodDelegate.createWithArgs(this, "createEntry", "John Doh");
processAddress(d);
}

public void processAddress(Delegate d) {
String address = "123 Nowhere Rd.";
d.invoke(address);
}

public void createEntry(String name, String address) {
...
}

Notice that at creation time of the Delegate "John Doh" is passed in. This is assigned in the Delegate instance as the first argument to the MethodDelegate. Now, when d.invoke is called in processAddress rather than requiring both name and address just address is necessary to be passed since name has already been assigned.

This makes it incredibly easy to put parameters into the method when you're ready to do so rather than applying everything in one place.

Delegates in xjava also make it easy to abstract away from the underlying way data is being retrieved or being assigned. For example, in the above processAddress method, it simply takes a Delegate and invokes it passing the address to it. If you decided later that you would rather assign this to a field of an object rather than calling a method you would simply replace someMethod with this:

public void someMethod() {
Delegate d = FieldDelegate.get(person, "address");
processAddress(d);
}

This presumes the "person" reference is an object with a String "address" field represented within it. The FieldDelegate doubles for getter and setter since passing a value will apply it to the field and invoking without any arguments will get the value from it.

There are also implementations for CallableDelegate and RunnableDelegate that are self-explanatory.

As seen by the interface for Delegate it is extremely easy to create your own implementations of Delegate for whatever scenario you may want to support and abstract away the details of where and what you are actually accessing and though this isn't as elegant as it could be if Java supported delegates natively, it still provides a very decent mechanism for abstracting and simplifying the process of passable work.

See the xjava project for more information:
http://xjava.googlecode.com

Feel free to look at the source code directly:
http://xjava.googlecode.com/svn/trunk/src/org/xjava/delegates/

1 comments:

romeosa said... @ July 8, 2009 at 4:01 AM

maybe it would be useful to have a delegate for GUI updating works, especially when you manage to use multiple threads

Post a Comment