我正在为一个游戏编写一个事件系统。下面是用于订阅频道的API示例。
Events.subscribe(Channel.COLLISION, new EventHandler<CollisionEvent>() {
@Override
public void handle(CollisionEvent event) {
}
});
和发布
Events.publish(Channel.COLLISION, new CollisionEvent(data));
将对象传递到发布方法时出现了问题。我从IDE收到一个警告,说发布方法中有一个未检查的调用。我正试图找到一种方法来检查,以确保对象的类型与EventHandler
的泛型类型兼容。如何确保event
的类型适合handler
(在下面的摘录中)?
Events.java
private static Map<Channel, ArrayList<EventHandler>> eventHandlers
= new HashMap<Channel, ArrayList<EventHandler>>();
public static void publish(EventType eventType, GameEvent event) {
ArrayList<EventHandler> handlers = eventHandlers.get(eventType);
if(handlers != null) {
for (EventHandler handler : handlers) {
handler.handle(event); // unchecked call warning occurs here
}
}
}
事件处理程序.java
public abstract class EventHandler<T extends GameEvent> {
public abstract void handle(T event);
}
您应该收到此警告-您可能会传入不同的事件类型。您可能需要决定如何构建解决方案-按原样,您可以更改它,以便EventHandler
对象上的handle
函数可以接收任何类型的事件,而不仅仅是EventHandler
参数化的事件,然后让EventHandler
检查它被要求处理的事件是否是它感兴趣的类型。或者,您可以将该类型的逻辑移动到事件发布者-每当事件发生时,for循环都可以检查它当前所在的事件处理程序是否支持该类型的事件,如果支持,则告诉它处理它。
我想问题是因为你的循环使用了一个非类型化的EventHandler,而它调用了一个泛型方法。
我会使用该列表作为
List<EventHandler<? extends GameEvent>>
for语句中的循环变量也是如此。
Thomas
更新:很抱歉,您正在查找事件类型,认为您不想要警告。
如果句柄方法中的类型感兴趣,那么让EventHandler来决定如何。如果速度太慢,请构建一个以GameEvent.class为键、以一个interested处理程序列表为值的Map。处理程序提供订阅时的事件列表。
更准确地说:您当前订阅事件的方式似乎表明,处理程序实现了正确的方法。然而,您的subscribe
方法并没有强制执行处理程序和订阅事件之间的关系。
如果您修改订阅以将处理程序不绑定到事件通道,而是绑定到事件本身,编译器将尽最大努力避免任何处理程序对正确的事件没有反应而访问通道:
public <T extends GameEvent> void subscribe(Class<T> clazz, EventHandler<T> handler)
在subscribe
实现中,您将处理程序放在一个列表中,该列表保存在一个映射中,用clazz键控。
if( !map.containsKey(clazz) ) {
map.put(clazz, new ArrayList<EventHandler<T>>());
}
// add the handler
map.get(clazz).add(handler);
publish
方法将使用给定的具体GameEvent.class
作为关键字,从映射中获得正确的列表,并调用所有处理程序。
通过在订阅期间调节访问权限,您在通话期间无需注意。如果有人使用肮脏的伎俩进入错误的列表,他应该崩溃,只要你不为原子弹编写代码;-)