简体   繁体   English

Java中的多态调度

[英]Polymorphically Dispatching in Java

In the following, I want EventHandler to handle EventA one way, EventB another way, and any other Events (EventC, EventD) yet another way. 在下文中,我希望EventHandler以一种方式处理EventA,以另一种方式处理EventB,以其他方式处理任何其他事件(EventC,EventD)。 EventReceiver receives only a reference to an Event and calls EventHandler.handle(). EventReceiver仅接收对事件的引用,并调用EventHandler.handle()。 The version that always gets called, of course, is EventHandler.handle(Event event). 当然,总是被调用的版本是EventHandler.handle(Event event)。

Without using instanceOf, is there a way to polymorphically dispatch (perhaps via another method in EventHandler or generics) to the appropriate handle method? 不使用instanceOf,是否有办法多态分派(也许通过EventHandler中的另一个方法或泛型)到适当的handle方法?

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

Sounds like a case for applying (a variant of) the Visitor pattern . 听起来像是应用Visitor模式的一种情况。 (In mainstream OO languages such as C++, C# and Java, methods are single dispatch , ie can only be polymorphic on one type at a time. Visitor allows one to implement double dispatch .) (在主流的OO语言(例如C ++,C#和Java)中,方法是单调度 ,即一次只能在一种类型上是多态的。访问者允许一个实现双调度 。)

This however requires that you be able to modify the Event classes as well, and creates a dependency from Event s to (a base interface of) EventHandler . 但是,这要求您还能够修改Event类,并创建从EventEventHandler (的基本接口)的依赖项。

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

This is a use case for double-dispatch , no (which as one may indeed know is either called Visitor) ? 这是双调度的用例,不是(您可能确实知道这称为“访客”)? I'll implement your example for EventA only 我将仅针对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 only has polymorphic dispatch on the object a method is invoked on. Java仅在调用方法的对象上具有多态调度。 That means, the only way to get real polymorphism is to put the handle() method into the Event interface itself. 这意味着,获得真实多态性的唯一方法是将handle()方法放入Event接口本身。 I'd actually say that is the overall better and more OO solution, since a "handler" that operates on data objects is rather procedural. 实际上,我会说这是整体上更好,更面向对象的解决方案,因为对数据对象进行操作的“处理程序”相当程序化。

Any other solution (like a map of handler objects keyed on the class) is going to be more complex and less flexible, especially concerning inheritance. 任何其他解决方案(例如在类上键入的处理程序对象的映射)都将变得更加复杂且灵活性较低,尤其是在继承方面。

I know how you can do it with some pre-processing. 我知道您可以通过一些预处理来做到这一点。 Use something like this: 使用这样的东西:

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

Then use a map to organize your handlers 然后使用地图来组织您的处理程序

HashMap<Class<?>,Collection<EventHandler<?>> handlers;

When an event needs to be handled just retrieve the handlers from the map. 当需要处理事件时,只需从地图中检索处理程序即可。 If Class.equals() and Class.hashCode() doesn't work how you want then you'll need a wrapper to get the behavior you want. 如果Class.equals()和Class.hashCode()不能按您希望的方式工作,则需要包装器才能获得所需的行为。

You could use a Map and map event types to event handlers. 您可以使用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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM