4

客观的

我正在尝试构建一个 MessageDispatcher,它将消息从 3rd 方 API 转换为用户定义的消息,然后将它们分派给用户注册的侦听器。

用户将被期望:

  1. 为每种类型的用户消息定义一个接口。
  2. 为每种消息类型向消息调度程序注册一个侦听器。
  3. 将原始/第 3 方数据传递给消息调度程序。
  4. 处理传递回侦听器的消息。

问题描述

不幸的是,我似乎无法避免使用原始类型来实现我想要的 API。我在别处读到,使用 Raw 类型没有例外情况,它们仅存在于语言中以实现向后兼容性。

有没有办法可以更改下面的代码以工作,或者我需要重新设计我的 API?

接口

MessageDispatcher 实现以下接口:

public interface MessageDispatcher {

    // Register a listener for a given user defined message type.
    public <T> void registerListener(
        Class<T> messageClass, 
        MessageListener<T> listener);

    // Receive data in 3rd party format, convert and dispatch.
    public void onData(Data data);

}

MessageListener 接口定义为:

public interface MessageListener<T> {

    public void onMessage(T message);   

}

示例用户消息可能如下所示:

public interface MyMessage {

    public String getName();   

}

注册监听器

用户可以按如下方式注册监听器:

messageDispatcher.registerListener(MyMessage.class, 
    new MessageListener<MyMessage.class>() {
    @Override

   public void onMessage(MyMessage message) {
        System.out.println("Hello " + message.getName());
    }
}

一个标准的消息调度器可能会实现这样的方法:

private Map<Class<?>,MessageListener<?>> messageClassToListenerMap;

public <T> void registerListener(
    Class<T> messageClass, 
    MessageListener<T> listener) {

    messageClassToListenerMap.put(messageClass, listener);

    // SNIP: Process the messageClass and extract the information needed
    // for creating dynamic proxies elsewhere in a proxy factory.

}

发送消息

当 MessageDispatcher 接收到新消息时,它会为该对象创建一个动态代理并将其分派给适当的侦听器。但这就是我的问题所在:

public void onData(Data data) {

    // SNIP: Use proxy factory (not shown) to get message class and
    // dynamic proxy object appropriate to the 3rd party data.
    Class<?> messageClass;  // e.g. = MyMessage.class;
    Object dynamicProxy;    // e.g. = DynamicProxy for MyMessage.class;

    // TODO: How to I pick the appropriate MessageListener and dispatch the
    // dynamicProxy in a type safe way?  See below.

}

如果我尝试使用我无法发送数据的类型:

// Assuming a listener has been registered for the example:
MessageListener<?> listener = messageClassToListenerMap.get(messageClass);

listener.onMessage(dynamicProxy); // ERROR: can't accept Object.
listener.onMessage(messageClass.cast(dynamicProxy); // ERROR: Wrong capture.

这是有道理的,因为我无法知道我的听众接受什么类型的数据以及我正在传递什么类型的数据。

但是,如果我使用原始类型,它可以正常工作:

// Assuming a listener has been registered for the example:
MessageListener listener = messageClassToListenerMap.get(messageClass);  
listener.onMessage(dynamicProxy); // OK, provided I always pass the correct type of object.
4

3 回答 3

1

你不能在这里使用泛型,因为只有在运行时才能知道确切的类型,所以你必须使用不安全的强制转换。原始类型不检查类型,因此它可以工作。泛型仅在编译时工作,您的调度程序在运行时工作。

所以,你应该明确地检查它:

MessageListener listener = messageClassToListenerMap.get(messageClass);  
if(!messageClass.isAssignableFrom(dynamicProxy.getClass()))
  throw new Something();
listener.onMessage(dynamicProxy);

我认为这是错误的设计。我建议做这样的事情:

interface MyMessageListener
{
  void onMessageA(String name);
  void onMessageB(String otherParam);
}

当您可以通过接口类和方法名称发送消息时。(你可以使用单一方法的接口,但不是那么好恕我直言)。此外,Spring 已经为它提供了基础设施:MethodInterceptorRemoteExporterRemoteInvocation一些相关的。

于 2012-01-10T15:21:42.323 回答
1

您不需要使用原始类型 - 只需将通配符类型转换为您想要的类型。这有点违背类型安全。它会给出一个未经检查的强制转换警告,你可以忽略它。但它证明了不使用原始类型是可能的。

MessageListener<Object> listener = (MessageListener<Object>)messageClassToListenerMap.get(messageClass);

listener.onMessage(dynamicProxy);
于 2012-01-11T02:58:49.137 回答
0

当我看到你的代码时我有一个烦恼,你为什么要为你使用消息类的代理...消息只是一个java bean来签署一个消息事件已经发生,你只需告诉听众,有某种类型消息发生了,你应该做一些事情来扮演听众的角色......这是一个消息的角色......我不知道为什么有一个消息的代理,这太令人惊讶了......

于 2012-01-10T15:25:09.723 回答