我正在尝试创建一个系统来响应应用程序中发生的事件,类似于Observer模式。在我的系统中,EventProducer的触发事件和EventConsumer响应这些事件,并且两者通过中央集线器连接:

目前,我将忽略EventProducer,而专注于EventHubEventConsumer:

interface EventConsumer<E extends Event> {
    void respondToEvent(E event);
}

class EventHub {
    private HashMap<Class</*event type*/>, HashSet<EventConsumer</*event type*/>>> subscriptions;
    public <E extends Event> void fireEvent(E event) {
        /* For every consumer in the set corresponding to the event type {
            consumer.respondToEvent(event);
        } */
    }
    public <E extends Event> void subscribeToEvent(EventConsumer<E> consumer) {
        /* Insert consumer into the set corresponding to E */
    }
}

问题出在HashMap的声明中:我希望能够做类似的事情
HashMap<Class<E extends Event>, HashSet<EventConsumer<E>>>
// or
<E extends Event> HashMap<Class<E>, HashSet<EventConsumer<E>>>

这样EventConsumer就可以通过Class的相同类型进行参数化,但是我能得到的最接近的是
HashMap<Class<? extends Event>, HashSet<EventConsumer<? extends Event>>>

但是,这将允许将HashSet<EventConsumer<MouseClickEvent>>Class<KeyPressEvent>子类KeyPressEvent都分配给MouseClickEvent之类的东西。

第二个问题是Event:我需要能够将使用者存储在与其事件对应的正确集中,例如
subscriptions.get(E.class).put(consumer)

但我在运行时无法获得E类。

我该如何解决这些问题?我会以错误的方式处理吗?

最佳答案

您可以从EventConsumer类中删除泛型。但是您必须在EventConsumer的每个实现中强制转换Event对象。

interface EventConsumer {
    void respondToEvent(Event event);
}

class ClickEventConsumer implements EventConsumer {
   public void respondToEvent(Event event){
     ClickEvent ce = (ClickEvent)event;
     //...
   }
}

class EventHub {
  private HashMap<Class<? extends Event>, HashSet<EventConsumer>> subscriptions;

  public void fireEvent(Event event) {
    HashSet<EventConsumer> consumers = subscriptions.get(event.getClass());
    if (consumers != null){
      for (EventConsumer ec : consumers){
        ec.respondToEvent(event);
      }
    }
  }

  public void subscribeToEvent(Class<? extends Event> clazz, EventConsumer consumer) {
    HashSet<EventConsumer> consumers = subscriptions.get(clazz);
    if (consumers == null){
      consumers = new HashSet<EventConsumer>();
      subscriptions.put(clazz, consumers);
    }
    consumers.add(consumer);
  }
}

10-07 12:16