[英]Avoid multiple loop in Observer code
我有一個類AllListener
來封裝多個Listener,如下所示。 問題是我必須在每個事件方法中編寫一個循環 ( onStart()
, onEnd()
)。 在觀察者模式代碼中這是很正常的方式,但它的味道很難聞。 有沒有更好的方法來編寫一次循環? 謝謝!
class AllListener{
List<Listener> listeners;
void onStart(){
for(Listener l:listeners)//loop
l.onStart();
}
void onEnd(){
for(Listener l:listeners)//loop
l.onEnd();
}
}
避免這種情況很難,因為Java仍然沒有關閉。 基本上你有這些選擇:
。
class AllListener{
List<Listener> listeners;
private interface Wrapper {
public void run(Listener l);
}
void onStart(){
loop(new Wrapper(){
public void run(Listener l) {
l.onStart();
});
}
void onEnd(){
loop(new Wrapper(){
public void run(Listener l) {
l.onEnd();
});
}
private void loop(Wrapper w) {
for(Listener l:listeners)
w.run(l);
}
}
正如您所看到的那樣,它可以工作,但與原始版本相比可讀性較差,如果您只有兩種調用方法則不值得。
您可以方便java的動態代理來解決此問題:
public class MultiListenerExample {
private ArrayList<OnClickListener> onClickListeners = new ArrayList<OnClickListener>(); private OnClickListener dispatcher;
public void performOnClick(View v) {
dispatch().onClick(v);
}
private OnClickListener dispatch() {
if (dispatcher == null) {
dispatcher = createDispatcher();
}
return dispatcher;
}
private OnClickListener createDispatcher() {
ClassLoader loader = OnClickListener.class.getClassLoader();
Class<?>[] interfaces = new Class[] { OnClickListener.class };
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
for (OnClickListener listener : onClickListeners) {
// safe to call this since we implement the same interface as the object of the original invocation
method.invoke(listener, args);
}
return null;
}
};
return (OnClickListener) Proxy.newProxyInstance(loader, intefaces, handler);
}
}
dispatch()
返回的接口上的每個調用都將傳播到以這種方式實現的InvocationHandler
對象中,它將遍歷偵聽器的容器,並將對每個項執行原始調用。
可以安全地調用該方法,因為原始調用是在我們將要調用的完全相同的接口上進行的。
只要您的偵聽器沒有返回值,此解決方案就可以正常工作。
您可以編寫一個包含循環的fire方法,並從onStart,onEnd方法中調用此方法,如下所示。
class AllListener {
void onStart(){
fire("onStart");
}
void onEnd(){
fire("onEnd");
}
// eventName must be same with the event handler method in Listener class.
private void fire(String eventName) {
for(Listener l : listeners) {
// Call event handler method with reflection.
l.getClass().getMethod(eventName).invoke(l);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.