Java 中的多态调度

发布于 2024-10-13 03:48:20 字数 830 浏览 8 评论 0原文

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

如果不使用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);
    }
}    

In the following, I want EventHandler to handle EventA one way, EventB another way, and any other Events (EventC, EventD) yet another way. EventReceiver receives only a reference to an Event and calls EventHandler.handle(). The version that always gets called, of course, is 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?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

十级心震 2024-10-20 03:48:20

听起来像是应用访问者模式(的变体)的案例。 (在主流的面向对象语言,如C++、C#和Java中,方法是单分派,即一次只能在一种类型上多态。访问者允许实现双分派 >.)

但是,这要求您也能够修改 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);
    }
}

Sounds like a case for applying (a variant of) the Visitor pattern. (In mainstream OO languages such as C++, C# and Java, methods are single dispatch, i.e. can only be polymorphic on one type at a time. Visitor allows one to implement double dispatch.)

This however requires that you be able to modify the Event classes as well, and creates a dependency from Events to (a base interface of) 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);
    }
}
寒尘 2024-10-20 03:48:20

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

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

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);
    }
}    
老子叫无熙 2024-10-20 03:48:20

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

任何其他解决方案(例如在类上键入的处理程序对象的映射)都将更加复杂且灵活性较差,尤其是在继承方面。

Java only has polymorphic dispatch on the object a method is invoked on. That means, the only way to get real polymorphism is to put the handle() method into the Event interface itself. 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.

夏九 2024-10-20 03:48:20

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

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

You could use a Map and map event types to event handlers.

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);
}
黎歌 2024-10-20 03:48:20

我知道如何通过一些预处理来做到这一点。使用如下内容:

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() 不能按您想要的方式工作,那么您将需要一个包装器来获得您想要的行为。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文