Direi che non è una buona idea permettere agli ascoltatori di aggiungere/rimuovere altri ascoltatori (o loro stessi). Indica una scarsa separazione delle preoccupazioni. Dopo tutto, perché l'ascoltatore dovrebbe sapere qualcosa sul chiamante? Come testeresti un sistema così strettamente accoppiato?
Invece, è possibile che il metodo di gestione degli eventi (nel listener) restituisca un flag booleano che indica che il listener non desidera ricevere più eventi. Ciò rende la rimozione da parte del dispatcher dell'evento e copre la maggior parte dei casi di utilizzo in cui è necessario modificare l'elenco degli ascoltatori da un listener.
La principale differenza in questo approccio è che l'ascoltatore dice semplicemente qualcosa su se stesso (ad esempio "Non voglio più eventi") piuttosto che essere legato all'implementazione del dispatcher. Questo disaccoppiamento migliora la testabilità e non espone l'interno di nessuna delle due classi all'altra.
public interface FooListener {
/**
* @return False if listener doesn't want to receive further events.
*/
public boolean handleEvent(FooEvent event);
}
public class Dispatcher {
private final List<FooListener> listeners;
public void dispatch(FooEvent event) {
Iterator<FooListener> it = listeners.iterator();
while (it.hasNext()) {
if (!it.next().handleEvent(event))
it.remove();
}
}
}
Aggiornamento: Aggiungere e rimuovere altri ascoltatori dall'interno di un ascoltatore è leggermente più problematico (e dovrebbe scattare campanelli d'allarme ancora più forte), ma si può seguire un modello simile: l'ascoltatore deve restituire informazioni su quali altri gli ascoltatori devono essere aggiunti/rimossi e il dispatcher deve agire su tali informazioni.
Tuttavia, in questo scenario si ottiene un bel paio di casi limite:
- quello che dovrebbe accadere con l'evento attuale?
- Dovrebbe essere inviato agli ascoltatori appena aggiunti?
- Dovrebbe essere spedito a chi sta per essere rimosso?
- Cosa succede se si sta tentando di rimuovere qualcosa che è in precedenza nell'elenco e l'evento è già stato inviato ad esso?
- Inoltre, cosa succede se il listener X aggiunge l'ascoltatore Y e quindi l'ascoltatore X viene rimosso? Dovresti andare con lui?
Tutti questi problemi derivano dal modello di listener stesso e dall'assunto di base che tutti gli ascoltatori nella lista saranno indipendenti l'uno dall'altro. E la logica per gestire questi casi dovrebbe sicuramente andare nel dispatcher e non nell'ascoltatore.
Aggiornamento 2: Nel mio esempio ho usato un booleano nudo per brevità ma nel codice reale definirei un tipo enum a due valori per rendere il contratto più esplicito.
Si prega di inviare una domanda più dettagliata con uno snippet di codice più grande per essere chiari. –
Non c'è 'listeners' una sorta di collezione (come una lista)? Se questo è il caso, [sappiamo di rimuovere quelli con un 'Iterator'.] (Http://stackoverflow.com/q/223918/1079354) – Makoto
Forse non sto rispondendo alla domanda, ma generalmente usando un FOR per rimuovere gli elementi di solito finiscono con un'eccezione. Dovresti usare un Iterator per rimuoverlo mentre si itera. – spekdrum