4

目的

サードパーティ API からのメッセージをユーザー定義メッセージに変換し、ユーザー登録リスナーにディスパッチする MessageDispatcher を構築しようとしています。

ユーザーには次のことが期待されます。

  1. ユーザー メッセージのタイプごとにインターフェイスを定義します。
  2. 各メッセージ タイプのメッセージ ディスパッチャーにリスナーを登録します。
  3. raw/サードパーティ データをメッセージ ディスパッチャに渡します。
  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<Object> listener = (MessageListener<Object>)messageClassToListenerMap.get(messageClass);

listener.onMessage(dynamicProxy);
于 2012-01-11T02:58:49.137 に答える
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 にはMethodInterceptor、 、RemoteExporterRemoteInvocationおよび関連するいくつかのインフラストラクチャが既にあります。

于 2012-01-10T15:21:42.323 に答える
0

私 は あなた の コード を 見 て 困っ て い ます . なぜ メッセージ クラス に プロキシ を 使う の でしょ う .メッセージが発生しました。リスナーの役割を実行するには、何かを行う必要があります...これはメッセージの役割です....メッセージのプロキシがある理由がわかりません。とても驚きます......

于 2012-01-10T15:25:09.723 に答える