我正在为游戏编写一个事件系统。以下是订阅频道的API示例。
Events.subscribe(Channel.COLLISION, new EventHandler<CollisionEvent>() {
@Override
public void handle(CollisionEvent event) {
}
});
并发布
Events.publish(Channel.COLLISION, new CollisionEvent(data));
将对象传递给publish方法时出现问题。我在IDE中收到有关发布方法中未经检查的调用的警告。我试图找到一种检查方法,以确保对象的类型与EventHandler
的通用类型兼容。如何确保event
的{{1}}类型正确(在下面的摘录中)?
handler
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
}
}
}
答案 0 :(得分:2)
你应收到此警告 - 您可能会传入不同的事件类型。您可能需要决定如何构建解决方案 - 您可以更改它,以便handle
对象上的EventHandler
函数可以接受任何类型的事件,而不仅仅是一个EventHandler
被参数化,然后EventHandler
检查它要求处理的事件是否是它感兴趣的类型。或者,你可以将这种类型的逻辑移动到事件发布者 - 每当事件发生时,for循环可以检查它当前所在的事件处理程序是否支持该类型的事件,如果是,请告诉它处理它。
答案 1 :(得分:1)
我认为问题是因为你的循环使用了无类型的EventHandler,而它调用了泛型方法。
我会将列表用作
List<EventHandler<? extends GameEvent>>
for语句中的循环变量相同。
托马斯
更新:对不起,您会查找事件类型,认为您不想要警告。
如果在handle方法中该类型很有趣,那么让EventHandler决定怎么样?如果速度太慢,请使用GameEvent.class作为键构建一个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
作为关键字从地图中获取正确的列表并调用所有处理程序。
通过在订阅期间调整访问权限,您无需在通话期间注意。如果有人使用肮脏的技巧进入错误的列表,他应该崩溃,只要你不写原子弹的代码;-)