1

我正在为参数化事件编写一个简单的事件系统,它使用Map从类到以Set该类作为参数的处理程序。我的理解是,我无法通过参数限制来定义键和值类型之间的关系,并且我会收到未经检查的强制转换警告,将元素从集合中拉出。

这是我目前拥有的:

public class Manager {
    private class Event<T> {
        // getSubject(), etc.
    }

    private interface Handler<T> {
        public T handleEvent(Event<T> event, T subject);
    }

    private final Map<Class<?>, Set<Handler<?>>> handlers = new HashMap<Class<?>, Set<Handler<?>>>();

    public <T> void post(final Event<T> event, final T subject) {
        final Class<?> type = subject.getClass();

        if (this.handlers.containsKey(type)) {
            for (Handler<?> handler : this.handlers.get(type)) {
                // unchecked cast
                ((Handler<T>) handler).handleEvent(event, subject);
            }
        }
    }

    public <T> void register(final Class<T> type, final Handler<T> handler) {
        if (!this.handlers.containsKey(type)) {
            this.handlers.put(type, new HashSet<Handler<?>>());
        }

        this.handlers.get(type).add(handler);
    }
}

是否可以避免这种未经检查的演员表?我的设计可能有缺陷吗?

我在这里和谷歌上花了相当长的时间,但无法找到完全涵盖这种安排的任何内容。

4

3 回答 3

1

如果事件类本身形成层次结构,则可以通过使用访问者模式来避免强制转换。这在 Java 中非常麻烦,但不需要强制转换。

于 2013-10-09T17:38:20.070 回答
1

@SuppressWarnings("unchecked")不幸的是,在这种情况下,您无能为力。

您的 map 声明中没有任何内容可以阻止您将 aClass<A>与 a关联Set<Handler<B>>,因此编译器不可能知道是否是这种情况。可悲的是,没有办法对java.util.Map.

如果您要实现自己的数据结构来允许这种强制执行(提供类似的方法Handler<T> getHandler(Class<T> type),您最终只会将未经检查的强制转换隐藏在该数据结构中并保持您的客户端代码干净。

附带说明一下,Map接口期望 aObject作为 等的参数get()containsKey()因此所有通用的东西无论如何都会丢失(即使您可以将键的通用类型与其对应的值相关联,这根本不可能)。

于 2013-10-09T19:23:01.813 回答
0

我的代码组织有点不同,广播者代码,相当于你的经理,但在我的 post() 代码中,我做了相当于

for (Handler<T> handler : this.handlers.get(type)) {
   do stuff ...
}

由于事件参数由 T 参数化,因此您可以将 添加<T>到 Handler。但是我通过猜测和失误做了很多花哨的泛型工作,YMMV ... :-)

ps 你的 register() 方法应该是同步的。

于 2013-10-09T17:43:09.213 回答