吨事件,缩小代码库的方法?

时间:2011-01-04 14:53:36

标签: java listener

在我的程序中,有近50个被抛出的事件。我遇到的问题是采用标准的方式接收事件。

我的第一个想法是使用通用接口,只是让侦听器实现它并将自己添加到侦听器队列中。 Unfortunately this meant that classes couldn't have multiple listeners due to type erasure and multiple inheritance issues。所以我删除了侦听器代码并重新开始。

我当前(和原创)的设置是为每个事件提供一个侦听器接口。例如

/**
 * Listener for {@link myproject.hooks.events.FingerEvent}events
 * @see myproject.hooks.events.Finger
 */
 public interface FingerListener extends Listener {
        /**
         * Invoked when an {@link myproject.hooks.events.FingerEvent}occurs
         * @param event The generated FingerEvent
         */
        public void onFinger(FingerEvent event);
}

它们都扩展了不包含任何方法的接口Listener,只是为了将它们全部统称为“监听器”。

这个问题是每个事件都有大量的代码。你有事件及其获取者(幸运的是,这是由Project Lombok简化的),然后是接收它的接口,然后接口上的javadoc,以便当有人想要信息时,他们知道从哪里获取信息。

我遇到的另一个问题是每个侦听器都有一个不同的方法名称,这会导致非常有趣的代码试图找出要调用的方法。它脆弱,缓慢(使用反射),看起来像垃圾。如果你不相信我,那么:

    public static boolean callListener(Event event, Listener listener) {            
            //Get base name of event
            String name = event.getClass().getSimpleName().split("Event")[0];

            //Try and get the correct method if it exists
            Method listenerMethod = null;
            try {
                    listenerMethod = listener.getClass().getMethod("on"+name, event.getClass());
            } catch (NoSuchMethodException ex) {
                    //Method doesn't exist, just don't call anything
                    return false;
            } catch (SecurityException ex) {
                    throw new RuntimeException("Method on"+name+" is unaccessable", ex);
            }

            //Now that we have the method, attempt to execute it
            try {
                    listenerMethod.invoke(listener, event);
            } catch (Exception ex) {
                    throw new RuntimeException("Unexpected error when invoking method on"+name);
            }

            //Method executed sucessfully, return true
            return true;
    }

这是否是在java中接收事件的标准方法:为每个事件设置一个监听器接口,然后创建spaghetti来调用相应的方法,或者我这样做完全错了吗?

2 个答案:

答案 0 :(得分:2)

至少可以通过简化向侦听器委派“事件处理”来摆脱反射/调用逻辑。监听器知道它可以处理的事件类型,因此只需在标记界面中添加一个方法,例如:

 public interface Listener {
   public boolean process(Event event);
 }

并更改代码如下:

 public static boolean callListener(Event event, Listener listener) {   
    return listener.process(event);
 }

现在,如果我们有一个了解事件BreakfastDinner的监听器,我们可以像这样实现它(在MealListener中):

public class MealListener implements Listener {

  @Override
  public boolean process(Event event) {
    if (event instanceof Breakfast) {
       this.onBreakfast((Breakfast) event);
       return true;
    }
    if (event instanceof Dinner) {
       this.onDinner((Dinner) event);
       return true;
    }
    return false; // MealListener ignores this event
  }

  private void onBreakfast(Breakfast breakfastCall) {
    // eat breakfast
  }

  private void onDinner(Dinner dinnerCall) {
    // eat dinner
  }

} 

顺便说一句 - 不要害怕“大量的课程” - 只需为所有事件和听众找到一个共同的源模式并自动生成源文件。在这种情况下,您不必维护单个事件和侦听器源文件,而只需维护代码生成器及其资源文件(基于文件的列表,其中包含所有事件和侦听器的基本名称)

答案 1 :(得分:0)

你的设计错了。无论什么类触发事件,都应该调用接口中定义的方法。

所以你的界面应该是这样的:

public interface FingerListener {
   public void listenerCallback(FingerEvent event);
}

然后您可以简单地遍历您的侦听器并为每个已注册的侦听器调用listenerCallback方法。

如果接收者需要区分不同类型的事件,我会向FingerEvent类添加一个“类型代码”属性,可以由接收者检查。