Цель
Я пытаюсь создать MessageDispatcher, который преобразует сообщения из стороннего API в определенные пользователем сообщения и затем отправляет их зарегистрированному слушателю.
Ожидается, что пользователь:
- определит интерфейс для каждого типа пользовательского сообщения.
- Зарегистрируйте слушателя в диспетчере сообщений для каждого типа сообщения.
- Передача необработанных / сторонних данных диспетчеру сообщений.
- Обработка сообщений, передаваемых обратно слушателям.
Описание проблемы
К сожалению, яне могу избежать использования необработанного типа для достижения желаемого 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.