2010-10-27 34 views
3

我有一个类AllListener来封装多个监听器,如下所示。 问题是我必须在每个事件方法(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(); 
    } 
} 

回答

1

避免这一点很难,因为Java仍然没有关闭。基本上,你有这些选择:

  • 使用一个包装类为您的“动作”
  • 到使用反射(我会考虑太这里复杂)
  • 使用库(如functionaljava

  • 使用Java的注释处理器[Little Bobby Tables学分]来生成代码。正如你所看到的那样,虽然起作用,但是与原始版本不太可读,如果你只有两种调用方法,就不值得麻烦。

  • +0

    还有第四种选择:使用Java的注释处理器生成代码。但是,除非你有几十个观察功能,否则这将是非常糟糕的做法。 – 2010-10-27 08:36:09

    +0

    正确,我忘记了。我会说这种复杂性与反思方法相似。 – Landei 2010-10-27 11:39:40

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

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

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