2013-11-21 5 views
1

У меня есть две петли, которые я пытаюсь реорганизовать в один метод. Петли уведомляют слушателей разных типов и объявляются как общие. Я думал, что смогу сделать это с некоторым отражением, но, похоже, я не могу об этом подумать.Литье класса и общего типа для использования в параметризованном типе

Вот мое сообщение класса и интерфейса слушателя:

public class Message { 

    private RequestType type; // Enum 
    private String data; 
    ... 
} 

public interface IRequestListener<T> { 
    public void resultUpdated(T result); 
} 

Вот петли:

... 
// Notification is an Enum 
for (IRequestListener<?> listener : listeners) { 
    IRequestListener<Notification> notificationListener = 
     (IRequestListener<Notification>) listener; 

    notificationListener.resultUpdated(Notification.valueOf(message.getData())); 
} 

... 

for (IRequestListener<?> listener : listeners) { 
     IRequestListener<Integer> notificationListener = 
      (IRequestListener<Integer>) listener; 

     notificationListener.resultUpdated(Integer.valueOf(message.getData())); 
} 

Вот моя отливка попытка решения которой, очевидно, неправильно:

... 

notifyMessageListeners(Notification.class, essage) 

... 

notifyMessageListeners(Integer.class, message); 

... 

private void notifyMessageListeners(Class clazz, Message message) { 
    LinkedList<IRequestListener<?>> listeners = 
     requestListenerMap.get(message.getType()); 

    for (IRequestListener<?> listener : listeners) { 

     // How to solve this cast? 
     // Error: unknown class: 'clazz' 
     IRequestListener<clazz> notificationListener = 
      (IRequestListener<clazz>) listener; 

     // How to solve the valueOf? Need to cast to a class which has valueOf()? 
     // Error: cannot resolve method valueOf 
     notificationListener.resultUpdated(clazz.valueOf(message.getData())); 
    } 
} 

Вот моя общая попытка решить, что тоже неправильно:

private void notifyMessageListeners(Message message) { 

    LinkedList<IRequestListener<?>> listeners = 
     requestListenerMap.get(message.getType()); 

    for (IRequestListener<?> listener : listeners) { 
     // Causes error 
     // resultUpdated (<?>) in IRequestListener cannot be applied to (java.lang.String) 
     listener.resultUpdated(message.getData()); 
    } 
} 

Я провел некоторое время на SO и в документах, пытаясь понять это. Кажется, что есть много сообщений о дженериках, но я не могу найти то, что я могу связать с моим конкретным вариантом использования.

Cheers.

EDIT:

решаемые с помощью принятого ответа.

notifyMessageListeners(message, new IValueGetter<T>() { 
    public T getValue(String data) { 
     return (T) Notification.valueOf(data); 
    } 
}); 

private void notifyMessageListeners(Message message, IValueGetter<T> getter) { 
    LinkedList<IRequestListener<?>> listeners = 
     requestListenerMap.get(message.getType()); 
    for (IRequestListener<?> listener : listeners) { 
     IRequestListener<T> notificationListener = (IRequestListener<T>) listener; 
     notificationListener.resultUpdated(getter.getValue(message.getData())); 
    } 
} 

ответ

2

Вот как исправить вашу первую попытку:

Во-первых, определить интерфейс для вызова valueOf (вы можете избежать этого с помощью отражения, но я думаю, что «безотражательным» подход чище)

interface ValueGetter<T> { 
    T getValue(String data); 
} 

Этот общий интерфейс позволяет передавать фрагмент кода notifyMessageListeners так что метод будет перезвонит Вам, чтобы извлечь нужное значение из строки.

private void notifyMessageListeners(Message message, ValueGetter<T> getter) { 
    LinkedList<IRequestListener<?>> listeners = 
     requestListenerMap.get(message.getType()); 

    for (IRequestListener<?> listener : listeners) { 
     IRequestListener<T> notificationListener = 
      (IRequestListener<T>) listener; 
     notificationListener.resultUpdated(getter.getValue(message.getData())); 
    } 
} 

Когда вы звоните notifyMessageListeners, вам необходимо пройти экземпляр ValueGetter<T>, как это:

notifyMessageListeners(message, new ValueGetter<T>() { 
    public T getValue(String data) { 
     return (T) Notification.valueOf(data); 
    } 
}); 

notifyMessageListeners(message, new ValueGetter<T>() { 
    public T getValue(String data) { 
     return (T) Integer.valueOf(data); 
    } 
}); 
+0

Спасибо, это, кажется, почти довести меня в рабочее состояние. Очень умно. Я удалил параметр 'Class', поскольку он не нужен. Я также добавил '' в мою подпись класса. Я получаю сообщение об ошибке: «Метод notifyMessageListeners (Message, ValueGetter ) в типе MyService не применим для аргументов (Message, new ValueGetter () {})'. Любое предложение о том, что может быть неправильным? – span

+0

Думаю, я мог бы это решить. См. Сообщение для редактирования, пожалуйста, если вы считаете, что это правильно. – span

+1

@rattmuff Да, это правильно: поскольку 'ValueGetter' параметризуется в том же типе' T', что и 'Class ', передача класса стала ненужной. – dasblinkenlight

Смежные вопросы