[注意:我已经查看了所有可能的重复项 - 没有一个是直接重复项,也没有提供这个特定问题的答案。]
我想为事件处理程序创建一个工厂,其中事件处理程序的泛型类型参数是事件类型。 事件类型仅在运行时已知。
在代码中,这是我想要实现的目标的说明:
public interface Event {
}
public interface EventHandler<T extends Event> {
void handle(T event);
}
public class EventHandlerFactory {
public <T extends Event> EventHandler<T> getHandler(Class<T> eventType) {
return ... // implementation?
}
}
然后能够以类型安全的方式使用事件,如下所示:
Event event = getEvent("some json representation");
factory.getHandler(event.getClass()).handle(event);
任何想法如何实现这一点(如果不可能,甚至是类似的东西)?
编辑:
具体的事件处理程序可能如下所示:
public class JobCreatedEventHandler implements EventHandler<JobCreatedEvent>
{
@Override
public void handle(JobCreatedEvent event) {
...
}
}
答案 0 :(得分:2)
使用访客模式的解决方案(根据评论中的要求):
public interface Event {
...
default void accept(EventHandlerFactory factory) {
factory.defaultHandle(this);
}
}
public class EventA implements Event {
public void accept(EventHandlerFactory factory) {
factory.handleA(this);
}
}
public class EventB implements Event {
public void accept(EventHandlerFactory factory) {
factory.handleB(this);
}
}
...
public class EventHandlerFactory {
public void handleEvent(Event e) {
e.accept(this);
}
public void handleA(EventA e) {
this.handlerA.handle(e);
}
public void handleB(EventB e) {
this.handlerB.handle(e);
}
...
public void defaultHandle(Event e) {
LOG.error("Handler method not defined for" + e.getClass().getSimpleName());
}
}
注意:
handleA
,handleB
等的可见性降低到EventFactory
的实际客户端类Event.accept
方法;在您的使用案例中,我认为EventHandlerFactory.defaultHandle
Event.handle
方法将调用返回到适当的getter方法,例如return factory.getEventHandlerForB
,如果您需要这种间接方式这个解决方案完全没有灵活性(几乎因为访问者模式是有史以来发明的最不灵活的模式),但它完成了工作。请注意,不需要按类进行单个强制转换/查找。
答案 1 :(得分:1)
只有
不可避免的问题是不要将地图放在Class<T>
到EventHandler<T>
上,而是放在较不安全的Class<? extends Event>
上 - 不能用成对类型安全映射。
nterface Event {
}
interface EventHandler<T extends Event> {
void handle(T event);
default void handleGen(Event event) {
handle((T)event);
}
}
class A implements Event {
}
class B implements Event {
}
class AHandler implements EventHandler<A> {
@Override
public void handle(A event) {
System.out.println("A");
}
}
class BHandler implements EventHandler<B> {
@Override
public void handle(B event) {
System.out.println("B");
}
}
工厂类:
// No type equality required between key and value handler's parameter.
private Map<Class<? extends Event>, EventHandler<? extends Event>> map = new HashMap<>();
public <T extends Event> void registerHandler(Class<T> eventType,
EventHandler<T> handler) {
map.put(eventType, handler);
}
public void handleEvent(Event event) {
Class<? extends Event> eventType = event.getClass();
EventHandler<? extends Event> handler = map.get(eventType);
if (handler != null) {
handler.handleGen(eventType.cast(event));
}
}
类型安全使用:
registerHandler(A.class, new AHandler());
registerHandler(B.class, new BHandler());
A a = new A();
handleEvent(a);
解决方案在handleGen中:
handler.handleGen(eventType.cast(event));
抽象基类可以包含一个包私有泛型方法handleGen
委托真正的句柄方法。由于注册方法,这在运行时是安全的。
答案 2 :(得分:0)
在某些时候,逻辑的某些部分需要认识到类A
的对象由类B
的对象处理,而类B
的对象需要有一个方法(为了论证而称为handleEvent()
,它(可能)出现在一个叫interface
的{{1}}中。
您是实现类型到实例的地图还是只是黑客攻击:
EventHandler
或Class<?> c=Class.forName(event.getClass().getName()+"Handler");
`else`语句的长链或类似的东西。
必须进行某种映射。
我没有看到解决方法。
答案 3 :(得分:0)
我会选择这样的东西。
public class EventHandlerFactory {
private HashMap<Class, EventHandler> map = new HashMap<>();
@SuppressWarnings("unchecked")
public <T extends Event> EventHandler<T> getHandler(Class<? extends T> eventType) {
return (EventHandler<T>) map.get(eventType);
}
public <T extends Event> setHandler(Class<? extends T> eventType, EventHandler<T> handler) {
map.put(eventType, handler);
}
}
地图不能强制执行类型安全,因此它由setter方法强制执行。事件类型只能映射到该类或其超类之一的处理程序。