这是可能的使用动态Proxy。
最简单的方法是将所需的界面作为第一个参数传递给您的Mux.create()
调用。否则,您将不得不使用反射来从所提供的所有具体侦听器实例中猜测所需的接口(难以确定所有侦听器对象是否实现了几个共同的接口)。
下面是它的短:
public class Mux {
/**
* @param targetInterface
* the interface to create a proxy for
* @param instances
* the concrete instances to delegate to
* @return a proxy that'll delegate to all the arguments
*/
@SuppressWarnings("unchecked")
public static <T> T create(Class<T> targetInterface, final T... instances) {
ClassLoader classLoader = targetInterface.getClassLoader();
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
for (T instance : instances) {
m.invoke(instance, args);
}
return null;
}
};
return (T) Proxy.newProxyInstance(classLoader,
new Class<?>[] { targetInterface }, handler);
}
}
,你会使用,例如,如下:
Apple apple = new Apple();
AppleListener l1 = new AppleListenerA();
AppleListener l2 = new AppleListenerB();
apple.setListener(Mux.create(AppleListener.class, l1, l2));
apple.doSomething(); // will notify all listeners
这是通过简单地创建一个动态Proxy
被强制转换为目标类型T
。该代理使用InvocationHandler
,该代理只将代理的所有方法调用委托给给定的具体实例。
注意,尽管在一般我完成所有的参数和局部变量只要有可能,我只有在这种情况下完成T... instances
强调这一事实,如果instances
是不决赛,然后引用它的匿名内部类中不会被允许(你会得到一个“不能引用在不同方法中定义的内部类中的非最终变量参数”)。
还要注意的是,上述假设的实际方法调用不返回任何有意义的(或有用的)值,因此handler
也返回null
所有方法调用。如果您想收集返回值并以有意义的方式返回这些值,则需要添加更多代码。
另外,可以检查所有给instances
以确定它们都实现了常用接口,并通过所有那些newProxyInstance()
。这使得Mux.create()
使用起来更加方便,并且失去了对其行为的一些控制。
/**
* @param instances
* the arguments
* @return a proxy that'll delegate to all the arguments
*/
@SuppressWarnings("unchecked")
public static <T> T create(final T... instances) {
// Inspect common interfaces
final Set<Class<?>> commonInterfaces = new HashSet<Class<?>>();
commonInterfaces.addAll(Arrays.asList(instances[0].getClass()
.getInterfaces()));
// Or skip instances[0]
for (final T instance : instances) {
commonInterfaces.retainAll(Arrays.asList(instance.getClass()
.getInterfaces()));
}
// Or use ClassLoader.getSystemClassLoader();
final ClassLoader classLoader = instances[0].getClass().getClassLoader();
// magic
final InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(final Object proxy, final Method m, final Object[] args)
throws Throwable {
for (final T instance : instances) {
m.invoke(instance, args);
}
return null;
}
};
final Class<?>[] targetInterfaces = commonInterfaces
.toArray(new Class<?>[commonInterfaces.size()]);
return (T) Proxy.newProxyInstance(classLoader, targetInterfaces,
handler);
}
如果所有侦听器都实现'AppleListener'接口,我不认为需要a)反射,也不b)泛型。只需把它们全部添加到你的''Mux''的'List'中并重复。或者我错过了什么? –
2013-04-08 05:48:16
您能解释一下关于您的多路复用器的更多信息吗?因为同样的事情出现在我的脑海里,正如阿利斯泰尔以色列所说的那样。 – 2013-04-08 05:49:39
尽管它稍微超出了预期的范围,但可以使用[Proxy](http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html)类。这创建了一个Object,它看起来像给出的类,但调用一个处理程序来处理它的调用,然后处理程序可以遍历这些侦听器。 – BevynQ 2013-04-08 06:13:39