使用 java 中的通用处理程序处理事件

发布于 2024-09-16 03:57:56 字数 1446 浏览 1 评论 0原文

我编写了自定义调度/处理事件系统,通常如下所示:

事件处理程序接口:

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) {...}
    ...
}

一切正常,但我想使用像

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);
}

现在这样的事件,当我向生成事件的管理器注册处理程序 DataChangeHandler 时对于字符串和整数,这个注册的处理程序将接收两个事件,当我想读取数据时,会导致 ClassCastException 发生。 我知道泛型没有一些特殊的类,并且尽管 DataChangeHandler 中定义了类型,但它们都存储在处理程序映射中的同一列表中。

有什么办法让它发挥作用吗?

I have written custom dispathing/handling event system that generally look like this:

Event handler interface:

public interface EventHandler{
}

Base event class:

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

Handler manager:

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) {...}
    ...
}

And everything is working fine but i want to use events like

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);
}

and now when I register handler DataChangeHandler with manager that generates events for Strings and for example for Integers, this registered handler will receive both events what causes ClassCastException to occure when I want to read data.
I understand that generic dont have some special class and that despite of type defined in DataChangeHandler they are stored in the same list in handlers map.

Is there any way to make it work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

◇流星雨 2024-09-23 03:57:56

这看起来真的是一个非常非常臭的设计。为什么应该使用处理该类型事件的类来键入事件?那是倒退了。事件处理程序应使用它处理的事件类型来键入。

所以我不太明白你实际上想要做什么,但我认为你基本上是在尝试这样做:

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);
        }
    }
}

这种类型的设计将过滤掉处理程序无法处理的事件。

This seems like a really, really smelly design. Why should an event be typed with the class that handles that type of event? That's backwards. An EventHandler should be typed with the type of Events it handles.

So I didn't quite follow what you're actually trying to do but I think you're basically trying to do this:

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);
        }
    }
}

This type of design will filter out events that the handler can't handle.

牵你手 2024-09-23 03:57:56

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

恕我直言:创建调度程序的一种更优雅的方法是使用注释。喜欢

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

Generics are largely a compile time feature. If you need the type at runtime you need to pass the class as an arguement and store it in a field.

IMHO: A more elegent way of creating a dispacter is to use an annotation. Like

@EventHandler
public void onMyEvent(MyEvent event) {
   // is called when MyEvent is dispacted.
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文