客观的

我正在尝试构建一个MessagedIsPatcher,该MesdissPatcher将消息从第三方API转换为用户定义的消息,然后将其分配给用户注册的侦听器。

将期望用户:

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

问题描述

不幸的是,我似乎无法避免使用原始类型来实现所需的API。我在其他地方读到,使用原始类型没有例外情况,并且它们仅在语言中存在以使其向后兼容。

有什么方法可以更改下面的代码工作,还是需要重新设计我的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.

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

但是,如果我使用RAW类型,则可以正常工作:

// 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.
有帮助吗?

解决方案

您不需要使用原始类型 - 只需将通配符类型投入到您想要的类型中即可。这有点面对类型的安全。它将发出不受限制的铸造警告,您可以忽略它。但这证明可以不使用原始类型。

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

listener.onMessage(dynamicProxy);

其他提示

您不能在此处使用仿制药,因为仅在运行时才知道精确的类型,因此您必须使用不安全的铸件。 RAW类型不检查类型,因此可以工作。仿制药仅在编译时间内工作,您的调度程序在运行时间内工作。

因此,您应该明确检查它:

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

当您可以通过接口类和方法名称派遣消息时。 (您可以将接口与单个方法使用,但恕我直言不太好)。此外,春天已经具有基础架构: MethodInterceptor, RemoteExporter, RemoteInvocation 还有一些相关。

当我看到您的代码时,我有一个trubble,为什么您为您的消息类使用代理...消息只是签署消息事件的Java bean,您只需告诉听众,有某种类型消息已经发生,您应该做一些事情来扮演侦听器的角色...这是一个消息的角色。...我不konw为什么有消息代理,这太惊讶了……

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top