用Java进行多态调度

在下文中,我希望EventHandler以一种方式处理EventA,以另一种方式处理EventB,以及以另一种方式处理任何其他事件(EventC,EventD)。 EventReceiver仅接收对Event的引用并调用EventHandler.handle()。 当然,总是被调用的版本是EventHandler.handle(事件事件)。

不使用instanceOf,有没有办法多态调度(可能通过EventHandler或generics中的另一个方法)到适当的句柄方法?

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); } } 

听起来像应用( 访问者模式的变体)的情况。 (在C ++,C#和Java等主流OO语言中,方法是单一调度 ,即一次只能在一种类型上进行多态。访问者允许实现双重调度 。)

但是,这要求您也能够修改Event类,并创建从Event s到( 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); } } 

这是一个双重调度的用例,没有(其中一个人可能确实称为访问者)? 我将仅为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); } } 

Java只对调用方法的对象进行多态分派。 这意味着,获得真正多态的唯一方法是将handle()方法放入Event接口本身。 我实际上说这是整体更好,更多的OO解决方案,因为对数据对象进行操作的“处理程序”是相当程序性的。

任何其他解决方案(如类关键字处理程序对象的映射)将变得更加复杂和灵活性,特别是在inheritance方面。

您可以使用Map并将事件类型映射到事件处理程序。

 Map, Handler> map = new HashMap, Handler>(); void receive(Event event) { Handler handler = map.get(event.getClass()); handler.handle(event); } 

我知道你如何通过一些预处理来做到这一点。 使用这样的东西:

 public abstract class EventHandler { public abstract void handle(T event, Class c); public abstract Class handles(); } public class EventHandlerA extends EventHandler { @Override public void handle(EventA event, Class c) { System.out.println(event); } @Override public Class handles() { return EventA.class; } } 

然后使用地图来组织处理程序

 HashMap,Collection> handlers; 

当需要处理事件时,只需从地图中检索处理程序即可。 如果Class.equals()和Class.hashCode()不能按您的方式工作,那么您需要一个包装器来获得您想要的行为。