這是可能的使用動態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