2014-04-04 122 views
0

我写事件源模板我的课:事件来源:短道火灾事件

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的那些方法,因为它是监听器无关。在SomeEventSource中编写这些方法使通用的EventSource比无用的更加无用。

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

+0

嗯......使用泛型确实不适用于通用事件处理。看看Java的Java类Observer和Observable。他们不是最好的,但也许你可以接管一些零件。 – Seelenvirtuose

+0

是的,Observer - Observerable比写自己的东西好。但它与方法(II)具有相同的缺点。如果有某种东西像std :: bind(我来自C++)绑定到一个函数并将其作为参数传递。 – Deepscorn

+0

Java 8? Lambda表达式? – Seelenvirtuose

回答

2

我想一般事件API应包括以下几件事:

  1. 类型安全,避免活动/事件类型类的铸造 - 它会节省你意想不到的造型异常的未来。
  2. 开发者友好。 API应该简短而甜蜜。您应该能够轻松地在您的IDE中找到正确的侦听器(例如Intellij IDEA或Eclipse)。类型安全会给你。
  3. 添加新的事件类型应该既简单又快速。
  4. 事件结构应该是可重用的。

这里是可能的方法之一:

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

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); 
+0

非常感谢!而已! – Deepscorn