在Observer代码中避免多次循环

时间:2010-10-27 07:58:26

标签: java oop observer-pattern

我有一个类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();
    }
}

3 个答案:

答案 0 :(得分:1)

避免这种情况很难,因为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);
    } 
 }

正如您所看到的那样,它可以正常工作,但与原始版本相比可读性较差,如果您只有两种调用方法则不值得。

答案 1 :(得分:0)

您可以编写一个包含循环的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);
        }
    }
}

答案 2 :(得分:0)

您可以使用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对象中,它将遍历侦听器的容器,并将执行原始调用每个项目。

可以安全地调用该方法,因为原始调用是在我们要调用的完全相同的接口上进行的。

只要您的听众没有返回值,此解决方案就可以正常工作。