2010-08-25 176 views
2

我已经写了自定义的dispathing /处理事件的系统,一般是这样的:事件在Java中使用通用处理程序处理

事件处理接口:

public interface EventHandler{ 
} 

基本事件类:

public abstract class Event<H extends EventHandler> { 
    public static Class Type<H> { } 
    public abstract void dispatch(H handler); 
} 

处理程序管理器:

public class HandlerManager { 
    private Map<Event.Type, List<EventHandler>> map = new HashMap<Event.Type, List<EventHandler>>(); 
    public void register(Event.Type<H> type, H handler) { 
     if(map.get(type) == null) { map.put(type, new ArrayList<EventHandler>()); } 
     map.get(type).add(handler); 
    } 

    public void fire(Event<H> event) {...} 
    ... 
} 

而且一切工作正常,但我想,当我注册处理DataChangeHandler与经理产生事件字符串和例如用于整数使用的事件,如

public class DataChangeEvent<D> extends Event<DataChangeHandler<D>> { 
    public static final Type<?> TYPE = new Type<?>(); 
    D data; 
    ... 
    public void dispatch(DataChangeHandler<D> handler) { 
     handler.onDataChanged(this); 
    } 
    public D getData() { return data; } 
} 

public class DataChangeHandler<D> extends EventHandler { 
    void onDataChanged(DataChangeEvent<D> event); 
} 

而现在,这个注册的处理程序将收到两个事件是什么原因发生ClassCastException时,我想要读取数据。 我明白泛型没有一些特殊的类,尽管在DataChangeHandler中定义了类型,但它们存储在处理程序映射中的同一个列表中。

有什么办法可以使它工作吗?

+0

从HandleManager中H是从哪里来的? – 2010-08-25 18:56:09

回答

3

这似乎是一个真的很臭的设计。为什么应该使用处理该类型事件的类来键入事件?这是倒退。一个EventHandler应该使用它处理的事件类型来输入。

所以我不太明白,你实际上试图做的,但我认为你基本上试图做到这一点:

private Map<Class<?>, List<EventHandler>> map; 
public <T> void register(Class<? extends T> typeFilter, EventHandler<T> handler) { 
    map.get(typeFilter).add(handler); 
} 


//...later 
//safe since we used a generic method to add 
@SuppressWarnings("unchecked"); 
public void fire(Event<?> event) { 
    for (EventHandler handler : map.get(event.getClass())) { 
     handler.onDataChanged(event); 
    } 
} 

//or similarly: 
@SuppressWarnings("unchecked"); 
public void fire(Event<?> event) { 
    for (Class<?> type : map.keySet()) { 
     if (!type.instanceOf(event)) continue; 
     for (EventHandler handler : map.get(type)) { 
      handler.onDataChanged(event); 
     } 
    } 
} 

这种类型的设计会过滤掉一些事件的处理程序没办法。

3

泛型在很大程度上是一个编译时功能。如果你在运行时需要这个类型,你需要将这个类作为一个参数传递并存储在一个字段中。

恕我直言:创建dispacter更加优雅的方式是使用注释。 Like

@EventHandler 
public void onMyEvent(MyEvent event) { 
    // is called when MyEvent is dispacted. 
}