簡體   English   中英

在Observer代碼中避免多次循環

[英]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仍然沒有關閉。 基本上你有這些選擇:

  • 為你的“行動”使用包裝類
  • 使用反射(我認為這里過於復雜)
  • 使用庫(例如functionaljava
  • 使用Java的注釋處理器生成代碼[信用: Little Bobby Tables ]

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM