在下文中,我希望EventHandler以一种方式处理EventA,以另一种方式处理EventB,以及另一种方式处理任何其他事件(EventC,EventD)。 EventReceiver仅接收对Event的引用并调用EventHandler.handle()。当然,总是被调用的版本是EventHandler.handle(事件事件)。
在不使用instanceOf的情况下,是否可以通过多态方式将调度(可能通过EventHandler或泛型中的其他方法)分配给相应的句柄方法?
class EventA extends Event {
}
class EventB extends Event {
}
class EventC extends Event {
}
class EventD extends Event {
}
class EventHandler {
void handle(EventA event) {
System.out.println("Handling EventA");
}
void handle(EventB event) {
System.out.println("Handling EventB");
}
void handle(Event event) {
System.out.println("Handling Event");
}
}
class EventReceiver {
private EventHandler handler;
void receive(Event event) {
handler.handle(event);
}
}
答案 0 :(得分:14)
听起来像应用Visitor pattern的变体一样。 (在主流的OO语言中,如C ++,C#和Java,方法是单一调度,即一次只能在一种类型上进行多态。访问者允许实现双重调度。)
然而,这要求您也能够修改Event
类,并创建从Event
到EventHandler
的基本接口的依赖关系。
class EventA extends Event {
public handleBy(EventHandler eh) {
eh.handleEventA(this);
}
}
class EventB extends Event {
public handleBy(EventHandler eh) {
eh.handleEventB(this);
}
}
class EventHandler {
void handleEventA(EventA event) {
System.out.println("Handling EventA");
}
void handleEventB(EventB event) {
System.out.println("Handling EventB");
}
void handle(Event event) {
event.handleBy(this);
}
}
答案 1 :(得分:2)
这是double-dispatch的一个用例,没有(因为人们可能知道它被称为访客)?我将仅为EventA实现您的示例
class Event {
/**
* Will do some type escalation
*/
void handleWith(EventHandler care) {
care.handle(this);
}
}
class EventA extends Event {
/**
* As event is EventA, this implementation is called, with its correct type forced by the cast
*/
void handleWith(EventHandler care) {
care.handle((EventA) this);
}
}
class EventHandler {
/**
* Finally comes here
*/
void handle(EventA event) {
System.out.println("Handling EventA");
}
void handle(EventB event) {
System.out.println("Handling EventB");
}
void handle(Event event) {
System.out.println("Handling Event");
}
/**
* Go here first and dispatch call to Event class
*/
void doHandle(Event event) {
event.handleWith(this);
}
}
class EventReceiver {
private EventHandler handler;
void receive(Event event) {
handler.doHandle(event);
}
}
答案 2 :(得分:1)
Java只对调用方法的对象进行多态分派。这意味着,获得真正多态性的唯一方法是将handle()
方法放入Event
接口本身。我实际上说这是整体更好,更多的OO解决方案,因为对数据对象进行操作的“处理程序”是相当程序化的。
任何其他解决方案(如类上键入的处理程序对象的映射)将变得更复杂且更不灵活,尤其是在继承方面。
答案 3 :(得分:0)
您可以使用Map并将事件类型映射到事件处理程序。
Map<Class<? extends Event>, Handler> map =
new HashMap<Class<? extends Event>, Handler>();
void receive(Event event) {
Handler handler = map.get(event.getClass());
handler.handle(event);
}
答案 4 :(得分:0)
我知道你如何通过一些预处理来做到这一点。使用这样的东西:
public abstract class EventHandler<T extends Event> {
public abstract void handle(T event, Class<T> c);
public abstract Class<T> handles();
}
public class EventHandlerA extends EventHandler<EventA> {
@Override
public void handle(EventA event, Class<EventA> c) {
System.out.println(event);
}
@Override
public Class<EventA> handles() {
return EventA.class;
}
}
然后使用地图来整理处理程序
HashMap<Class<?>,Collection<EventHandler<?>> handlers;
当需要处理事件时,只需从地图中检索处理程序即可。如果Class.equals()和Class.hashCode()没有按你想要的方式工作,那么你需要一个包装器来获得你想要的行为。