如何为事件侦听器模式在 java 中创建和激发 Consumers<T> 的集合
How to create and fire a collection of Consumers<T> in java for an event listener pattern
我正在尝试创建一个非常标准的事件 listener/broadcast 系统。现在只是尝试不同的想法,看看它们在我们的领域中是如何工作的。
我遇到的问题是我似乎无法找到使用泛型调用消费者的正确语法。
private ConcurrentHashMap<Class<? extends Event>, ConcurrentLinkedQueue<Consumer<? extends Event>>> listeners;
public <T extends Event> void listen(Consumer<T> consumer, Class<T> clazz){
ConcurrentLinkedQueue<Consumer<? extends Event>> consumers = listeners.get(clazz);
if (consumers == null) {
consumers = new ConcurrentLinkedQueue<>();
listeners.put(clazz, consumers);
}
consumers.add(consumer);
}
public <T extends Event> void fire(T eventToFire, Class<T> clazz){
ConcurrentLinkedQueue<Consumer<? extends Event>> consumers = listeners.get(clazz);
if(consumers != null){
consumers.forEach(x -> x.accept(eventToFire));// <-- This blows up saying that Consumer expects type T, but I'm passing it ? extends Event
}
}
调用它的正确方法是什么,或者我是否坚持必须为 ConcurrentLinkedQueue 使用对象?我试过抑制警告,但这似乎是一个更深层次的问题。
那是因为编译器不知道您在 listen
方法中确保映射的键和值都由相同的 T
参数化。就其所知,两者都是 ? extends Event
的两种类型可能彼此不兼容。
解决此问题的唯一方法是使用显式强制转换:
consumers.stream()
.map(c -> (Consumer<T>)c )
.forEach(c -> c.accept(eventToFire));
另外注意,listen
方法可以重写为:
listeners.computeIfAbsent(clazz, x -> new ConcurrentLinkedQueue<>())
.add(consumer);
不仅更短,而且与显式检查 null 不同,它是线程安全的。
此外,fire
方法不需要将Class<T>
作为参数。您可以使用 listeners.get(eventToFire.getClass())
我正在尝试创建一个非常标准的事件 listener/broadcast 系统。现在只是尝试不同的想法,看看它们在我们的领域中是如何工作的。
我遇到的问题是我似乎无法找到使用泛型调用消费者的正确语法。
private ConcurrentHashMap<Class<? extends Event>, ConcurrentLinkedQueue<Consumer<? extends Event>>> listeners;
public <T extends Event> void listen(Consumer<T> consumer, Class<T> clazz){
ConcurrentLinkedQueue<Consumer<? extends Event>> consumers = listeners.get(clazz);
if (consumers == null) {
consumers = new ConcurrentLinkedQueue<>();
listeners.put(clazz, consumers);
}
consumers.add(consumer);
}
public <T extends Event> void fire(T eventToFire, Class<T> clazz){
ConcurrentLinkedQueue<Consumer<? extends Event>> consumers = listeners.get(clazz);
if(consumers != null){
consumers.forEach(x -> x.accept(eventToFire));// <-- This blows up saying that Consumer expects type T, but I'm passing it ? extends Event
}
}
调用它的正确方法是什么,或者我是否坚持必须为 ConcurrentLinkedQueue 使用对象?我试过抑制警告,但这似乎是一个更深层次的问题。
那是因为编译器不知道您在 listen
方法中确保映射的键和值都由相同的 T
参数化。就其所知,两者都是 ? extends Event
的两种类型可能彼此不兼容。
解决此问题的唯一方法是使用显式强制转换:
consumers.stream()
.map(c -> (Consumer<T>)c )
.forEach(c -> c.accept(eventToFire));
另外注意,listen
方法可以重写为:
listeners.computeIfAbsent(clazz, x -> new ConcurrentLinkedQueue<>())
.add(consumer);
不仅更短,而且与显式检查 null 不同,它是线程安全的。
此外,fire
方法不需要将Class<T>
作为参数。您可以使用 listeners.get(eventToFire.getClass())