目的
サードパーティ API からのメッセージをユーザー定義メッセージに変換し、ユーザー登録リスナーにディスパッチする MessageDispatcher を構築しようとしています。
ユーザーには次のことが期待されます。
- ユーザー メッセージのタイプごとにインターフェイスを定義します。
- 各メッセージ タイプのメッセージ ディスパッチャーにリスナーを登録します。
- raw/サードパーティ データをメッセージ ディスパッチャに渡します。
- リスナーに返されるメッセージを処理します。
問題の説明
残念ながら、目的の 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.