Domanda

Obiettivo

Sto cercando di costruire un MessageDispatcher che converte i messaggi provenienti da un terzo partito API di messaggi definiti dall'utente e poi li invia ad un utente registrato ascoltatore.

L'utente sarà chiamato a:

  1. Definire un'interfaccia per ogni tipo di messaggio utente.
  2. Registra un ascoltatore con il dispatcher messaggio per ogni tipo di messaggio.
  3. Passo raw / dati 3rd party in al dispatcher messaggio.
  4. messaggi Maniglia passato al ascoltatori.

Descrizione del problema

Purtroppo non posso sembrare di evitare l'uso di un tipo grezzo per raggiungere il mio API desiderato. Ho letto altrove che non ci sono casi eccezionali per l'utilizzo di tipi prime ed esistono solo in lingua per la compatibilità all'indietro.

C'è un modo posso cambiare il codice sottostante per lavoro o devo per ri-progettare la mia API?

Interfacce

Gli strumenti MessageDispatcher la seguente interfaccia:

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

}

L'interfaccia MessageListener è definito come:

public interface MessageListener<T> {

    public void onMessage(T message);   

}

Un messaggio esempio utente potrebbero apparire così:

public interface MyMessage {

    public String getName();   

}

Gli ascoltatori Registrazione

L'utente può registrare un ascoltatore come segue:

messageDispatcher.registerListener(MyMessage.class, 
    new MessageListener<MyMessage.class>() {
    @Override

   public void onMessage(MyMessage message) {
        System.out.println("Hello " + message.getName());
    }
}

Un messaggio dispatcher standard potrebbe implementare il metodo come questo:

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.

}

dispacciamento Messaggi

Quando un nuovo messaggio viene ricevuto dal MessageDispatcher crea un proxy dinamica per l'oggetto e l'invia ad un ascoltatore appropriata. Ma questo è dove il mio problema è il seguente:

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.

}

Se provo e utilizzare il tipo non riesco a inviare i dati:

// 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.

Ha senso, perché non c'è modo posso sapere quale tipo di dati il ??mio ascoltatore accetta e quale tipo di dati che sto passando.

Ma se io uso i tipi prime funziona benissimo:

// 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.
È stato utile?

Soluzione

Non c'è bisogno di utilizzare i tipi di prime - appena gettato i tipi di caratteri jolly in un tipo che fa quello che si vuole. Questo vola pò a fronte di sicurezza tipo. E darà un avvertimento fusione incontrollata, che si può ignorare. Ma dimostra che è possibile non utilizzare i tipi grezzi.

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

listener.onMessage(dynamicProxy);

Altri suggerimenti

Non è possibile utilizzare farmaci generici qui, perché il tipo esatto è conosciuto solo in fase di esecuzione, quindi bisogna usare getto pericoloso. tipi prime non controllano i tipi, quindi funziona. Generics funziona solo in fase di compilazione, le tue opere dispatcher in fase di esecuzione.

Quindi, si dovrebbe verificare esplicitamente:

MessageListener listener = messageClassToListenerMap.get(messageClass);  
if(!messageClass.isAssignableFrom(dynamicProxy.getClass()))
  throw new Something();
listener.onMessage(dynamicProxy);

Penso che sia sbagliato il design. Suggerirei fare qualcosa di simile:

interface MyMessageListener
{
  void onMessageA(String name);
  void onMessageB(String otherParam);
}

quando si poteva inviare messaggi dalla classe di interfaccia e il nome del metodo. (È possibile utilizzare le interfacce con il metodo unico, ma non così bello imho). Inoltre, la primavera è già un'infrastruttura per esso:. MethodInterceptor, RemoteExporter, RemoteInvocation e alcuni correlata

ho un Trubble quando ti vedo codice, perché si usa il proxy per voi classe di segnalazione ... il messaggio è solo un bean Java per firmare un evento messaggio era accadere, basta dire l'ascoltatore che, non v'è un qualche tipo di messaggio era accaduto, si dovrebbe fare qualcosa per avere il ruolo di fare un ascoltatore ... questo è il ruolo di un messaggio .... non konw perché c'è un proxy per il messaggio, così sorpresa ..... .

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top