事件来源:触发事件的简短方法

时间:2014-04-04 05:30:41

标签: java events listener

我正在为我的课程编写事件源模板:

public class EventSource<E> {
  protected ArrayList<E> listeners = new ArrayList<E>();

  public void addListener(E listener)
  {
    listeners.add(listener);
  }

  public void removeListener(E listener)
  {
    listeners.remove(listener);
  }
}

要发起一个事件我需要调用类似的东西:

for(SomeListener listener: listeners)
  listener.onSomeEvent();

发起一个事件看起来很难看。有没有办法把更短的东西称为:

fire(SomeListener.onSomeEvent)

fire(onSomeEvent)

我已经找到了3个解决方案:

我使用java反射并将方法名称作为参数传递给模板中的某个方法,这将为所有侦听器调用此方法。但我认为由于需要解析字符串(方法名称)而效率低下。如何以不丑的方式传递参数 - 问题仍然存在。

II对所有方法使用相同的名称,但传递不同的参数:

public struct SomeEvent1
{
  int someData;
}

public struct SomeEvent2
{
  int someAnotherData;
  double probablyMoreData;
}

public interface SomeListener
{
  public void fire(SomeEvent1 e);
  public void fire(SomeEvent2 e);
}

但即使我不需要任何参数,它也需要构建此事件结构。

III使用授权。想象一下,SomeEventSource扩展了EventSource。现在我可以调用onSomeEventI(),因为我在SomeEventSource中编写了这些方法:

public void onSomeEventI()
{
  for(SomeListener listener: listeners)
    listener.onSomeEventI();
}

但我无法在通用EventSource中编写这些方法,因为它与Listener无关。在SomeEventSource中编写这些方法会使通用的EventSource更有用,而不是有用的。

问题仍然存在:如何在短时间内发射事件?

1 个答案:

答案 0 :(得分:2)

我认为事件API 通常应涵盖以下内容:

  1. 安全类型,避免投射事件/事件类型类 - 它将使您免于将来意外的类强制转换异常。
  2. 开发人员友好。 API应该简短而且甜美。您应该能够在IDE中轻松找到合适的侦听器(例如Intellij IDEA或Eclipse)。类型安全将给你。
  3. 添加新的事件类型应该简单快捷。
  4. 事件结构应该是可重用的。
  5. 以下是可能的方法之一:

    创建基本事件和更复杂的事件结构。

    class BaseEvent {
    }
    
    class ComplexEvent extends BaseEvent {
        int importantData;
        public ComplexEvent(int i) {
            importantData = i;
        }
    }
    

    EventType 创建单独的类,使每个事件类型都依赖于事件。我们现在可以为我们的事件类型重用现有结构。在不破坏现有代码的情况下添加新事件也非常容易。

    final class EventType<E> {
        private EventType(){}
        public final static EventType<BaseEvent> SimpleEvent = new EventType<BaseEvent>();
        public final static EventType<BaseEvent> SimpleEvent2 = new EventType<BaseEvent>();
        public final static EventType<ComplexEvent> ComplexEvent1 = new EventType<ComplexEvent>();
        public final static EventType<ComplexEvent> ComplexEvent2 = new EventType<ComplexEvent>();
    }
    

    创建侦听器作为通用接口,取决于事件。

    interface Listener<E extends BaseEvent> {
        void handle(E event);
    }
    

    EventSource 中使用此类,为指定的事件类型注册侦听器。

    class EventSource {
    
        private final Map<EventType, List<Listener<? extends BaseEvent>>> listenersMap = new HashMap<EventType, List<Listener<? extends BaseEvent>>>();
    
        public <E extends BaseEvent> void addListener(EventType<E> eventType, Listener<E> listener) {
            listeners(eventType).add(listener);
        }
    
        public <E extends BaseEvent> void fire(EventType<E> eventType, E event) {
            for (Listener listener : listeners(eventType)) {
                listener.handle(event);
            }
        }
    
        private List<Listener<? extends BaseEvent>> listeners(EventType eventType) {
            if (listenersMap.containsKey(eventType)) {
                return listenersMap.get(eventType);
            } else {
                List<Listener<? extends BaseEvent>> listenersList = new ArrayList();
                listenersMap.put(eventType, listenersList);
                return listenersList;
            }
        }
    
    }
    

    检查API的使用情况,它允许我们在Listener的实现中获得正确的事件结构。

    public static void main(String[] args) {
            EventSource eventSource = new EventSource();
            eventSource.addListener(EventType.SimpleEvent, new Listener<BaseEvent>() {
                @Override
                public void handle(BaseEvent event) {
                    log.info("Simple 1 handled!");
                }
            });
            eventSource.addListener(EventType.SimpleEvent2, new Listener<BaseEvent>() {
                @Override
                public void handle(BaseEvent event) {
                    log.info("Simple 2 handled!");
                }
            });
            // compile error! we must handle ComplexEvent type
    //        eventSource.addListener(EventType.ComplexEvent1, new Listener<BaseEvent>() {
    //            @Override
    //            public void handle(BaseEvent event) {
    //                log.info("Complex 1 handled!");
    //            }
    //        });
            eventSource.addListener(EventType.ComplexEvent1, new Listener<ComplexEvent>() {
                @Override
                public void handle(ComplexEvent event) {
                    log.info("Complex 1 handled!" + event.importantData);
                }
            });
            eventSource.addListener(EventType.ComplexEvent2, new Listener<ComplexEvent>() {
                @Override
                public void handle(ComplexEvent event) {
                    log.info("Complex 2 handled!" + event.importantData);
                }
            });
            eventSource.fire(EventType.SimpleEvent, new BaseEvent());
            eventSource.fire(EventType.SimpleEvent2, new BaseEvent());
            eventSource.fire(EventType.ComplexEvent1, new ComplexEvent(1));
            eventSource.fire(EventType.ComplexEvent2, new ComplexEvent(2));
            // compile error! we must fire ComplexEvent to our listeners
            //eventSource.fire(EventType.ComplexEvent1, new BaseEvent());
        }
    

    当您不需要传递任何特定数据时,您还可以向fire添加速记EventSource来电

    public <E extends BaseEvent> void fire(EventType<E> eventType) {
        fire(eventType, (E) new BaseEvent());
    }
    

    从客户端代码中使用它很简单:

    eventSource.fire(EventType.SimpleEvent);