オーバーロードするとややこしいことになるな…
追記
これをMixinと呼んでいいのか、ちょっと疑問に思えてきた。
拡張というより、二つのインスタンスを合体させているだけだし…
public interface Cat {String meow();
String run();
}
public class CatImpl implements Cat {
public String meow() {
return "cat.meow";
}public String run() {
return "cat.run";
}}
public interface Car {String light();
String run();
}
public class CarImpl implements Car {
public String light() {
return "car.light";
}public String run() {
return "car.run";
}}
public class MixinTest extends TestCase {public void testMixin() {
Object catCar = Mixin.create(new Object { new CarImpl(), new CatImpl() });Cat cat = (Cat) catCar;
assertEquals("cat.meow", cat.meow());
assertEquals("cat.run", cat.run());Car car = (Car) catCar;
assertEquals("car.light", car.light());
assertEquals("cat.run", car.run());assertEquals("$Proxy0", catCar.getClass().getName());
}}
public class Mixin {public static Object create(Object objects) {
Class interfaces = getInterfaces(objects);InvocationHandler handler = new MixinInvocationHandler(objects);
return Proxy.newProxyInstance(Mixin.class.getClassLoader(), interfaces, handler);
}private static Class getInterfaces(Object objects) {
Set buffer = new HashSet();for (int i = 0; i < objects.length; i++) {
Class interfaces = objects[i].getClass().getInterfaces();for (int j = 0; j < interfaces.length; j++)
buffer.add(interfaces[j]);
}return (Class) buffer.toArray(new Class[buffer.size()]);
}}
class MixinInvocationHandler implements InvocationHandler {
private Map objectMap = new HashMap();
private Map methodMap = new HashMap();
public MixinInvocationHandler(Object objects) {
for (int i = 0; i < objects.length; i++) {
Method methods = objects[i].getClass().getMethods();for (int j = 0; j < methods.length; j++) {
String name = methods[j].getName();
objectMap.put(name, objects[i]);
methodMap.put(name, methods[j]);
}
}
}public Object invoke(Object proxy, Method method, Object args) throws Throwable {
String name = method.getName();
Object object = objectMap.get(name);if (object == null)
return null;Method methodImpl = (Method) methodMap.get(name);
return methodImpl.invoke(object, args);
}}