/** * An interface for classes that need to dispatch dynamically on some method by * using the ConcreteDispatcher * * Implementing classes would overload the dispatch(Object o) method for all the * special cases, while having their own entry method - e.g. 'visit(Object o)' * or 'execute(SomeInterface s)' that would call the * ConcreteDispatcher.dispatch() method. This method calls back on the correct * dispatch() implementation. * * @author hrehfeld * */public interface Dispatcher { /** * The name of the dispatching method */ public static final String METHOD = "dispatch"; /** * All classes need the fallback operating on Object o. * * @param o * The Object to dispatch on */ void dispatch(Object o);}import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * A Class that provides a static way to double dispatch * * Large portions of this code were taken from http://www.javaworld.com/javaworld/javatips/jw-javatip98.html * and adjusted to be used in a more general and easy way * * @author hrehfeld * */public class ConcreteDispatcher { /** * A Static way to do double dispatching * * Dispatching looks for overloaded Dispatcher.METHOD() methods in the following order: * 1) the object's class * 2) the object's super-classes (bottom-up) * 3) the interfaces the object implements. Order is undefined, thus this might throw an {@link InvocationTargetException}, when the Dispatcher implements methods for more than one of the implemented interfaces, but no methods that would be found in step 1) or 2). * * @param dispatcher The dispatcher to call methods on * @param object Some object to dispatch on * @throws InvocationTargetException When the object implements two interfaces the Dispatcher provides overloaded methods for (and the Dispatcher doesn't provide more specialised methods), behaviour is undefined */ public static void dispatch(Dispatcher dispatcher, Object object) throws InvocationTargetException { Method method = ConcreteDispatcher.getMethod(dispatcher,Dispatcher.METHOD, object.getClass()); try { method.invoke(dispatcher, new Object[] {object}); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Find the most appropriate method to call on the Dispatcher for some object's class * * @param dispatcher The dispatcher to check * @param methodName The name of the dispatching method * @param class_ Class of the object to dispatch on the Dispatcher * @return a Method for the className * @throws InvocationTargetException */ @SuppressWarnings("unchecked") private static Method getMethod(Dispatcher dispatcher, String methodName, Class class_) throws InvocationTargetException { Class newc = class_; Method method = null; // Try the superclasses while (method == null && newc != Object.class) { try { method = dispatcher.getClass().getMethod(methodName, new Class[] { newc }); } catch (NoSuchMethodException e) { newc = newc.getSuperclass(); } } // Try the interfaces. If necessary, you // can sort them first to define 'visitable' interface wins // in case an object implements more than one. if (newc == Object.class) { int matches = 0; for (Class i: class_.getInterfaces()) { try { method = dispatcher.getClass().getMethod(methodName, new Class[] { i }); matches++; } catch (NoSuchMethodException e) { } } // more than one match if (matches > 1) { throw new InvocationTargetException(new Exception("Error: while trying to dispatch on the interfaces, there's " + matches + " possible matches. Behaviour is undefined.")); } } if (method == null) { try { method = dispatcher.getClass().getMethod(methodName, new Class[] {Object.class}); } catch (Exception e) { throw new InvocationTargetException(new Exception("Dispatcher doesn't implement " + methodName + "(Object o)!")); } } return method; }}public interface Foo {}public class AFoo implements Foo {}public class BFoo implements Foo {}import java.lang.reflect.InvocationTargetException;public interface Executor { void execute(Foo f) throws InvocationTargetException; }import java.lang.reflect.InvocationTargetException;public class DispatchExecutor implements Executor, Dispatcher { public void dispatch(AFoo o) { System.out.println("Dispatcher AFoo"); } public void dispatch(BFoo o) { System.out.println("Dispatcher BFoo"); } public void dispatch(Object o) { System.out.println("Dispatcher Object"); } @Override public void execute(Foo f) throws InvocationTargetException { ConcreteDispatcher.dispatch(this, f); } public static void main(String[] args) throws InvocationTargetException { Foo a = new AFoo(); Foo b = new BFoo(); DispatchExecutor d = new DispatchExecutor(); d.execute(a); d.execute(b); }}outputs:Dispatcher AFooDispatcher BFoo