Qual è la differenza tra il modello di osservatore e gli ascoltatori?

0

Ho usato una sorta di "ascoltatori" in cui ho un'interfaccia implementata da classi che devono essere notificate di qualche evento (ad es. CurrencyListener, con un metodo currencyUpdated (Valuta valuta) ) Quindi, l'oggetto che deve inviare una notifica, ha un elenco di listener (Elenco) e scorre semplicemente su questo elenco richiamando il metodo currencyUpdated (Valuta valuta) .

La struttura di questo listener, è molto simile al pattern Observer, non esiste una classe Observer and Observable, solo l'interfaccia listener (CurrencyListener).

Quali sono i vantaggi / gli svantaggi dell'utilizzo di un approccio rispetto all'altro?

    
posta user315772 20.09.2018 - 22:50
fonte

2 risposte

2

Questo è il pattern Observer - è la stessa identica cosa.

I have used some kind of "listeners" where I have an interface implemented by classes that need to be notified of some event (e.g.: CurrencyListener, with a method currencyUpdated(Currency currency))

Nel pattern Observer, hai un'astrazione (un'interfaccia o una classe base) Observer che definisce le cose che l'osservatore può osservare (o ascoltare). Il tuo CurrencyListener è Observer .

L'altra parte del pattern è Observable , che è l'oggetto che invia notifiche, che possono essere o meno un'astrazione, o parte di una gerarchia. Ad esempio, il modello non richiede che siano presenti le sottoclassi ConcreteObservable. Nel libro Modelli Go4, uno dei ruoli per un oggetto ConcreteObservable è descritto come

"stores state of interest to ConcreteObserver objects."

Se un ConcreteObserver non può aver bisogno di uno stato speciale, o può funzionare con l'interfaccia fornita dalla classe base Observable, allora non c'è bisogno di per un ConcreteObservable.

Then, the object that needs to send a notification, has a list of listeners (List) and just iterates over this list invoking the currencyUpdated(Currency currency) method

Observer fornisce metodi per Observables / Listeners per registrarsi con esso e mantiene internamente una collezione di questi listener. Questo è esattamente ciò che fa il tuo oggetto.

Ancora una volta, è solo il classico modello di Osservatore. Gli osservatori e gli osservabili sono indipendenti l'uno dall'altro perché dipendono entrambi dall'astrazione fornita dall'interfaccia Observer e perché si basano sul codice client che li utilizza per collegare gli osservatori / ascoltatori con l'osservabile.

P.S. C'è una serie di variazioni sul pattern e un numero di feature in diverse lingue che sono solo il pattern Observer travestito. Ad esempio, in C #, gli eventi sono chiaramente una variazione del modello. Un altro esempio di variazione potrebbe essere quello che viene solitamente chiamato Messenger (o Event Aggregator, come lo chiama Martin Fowler), può essere trovato in alcune librerie e framework - è una classe che funge da intermediario tra gli osservatori e gli osservabili . La struttura è leggermente diversa, ma è basata sul pattern Observer; infatti, il libro Go4 descrive qualcosa di simile vicino alla fine della sezione Implementazione nella descrizione del pattern (lo chiamano ChangeManager).

    
risposta data 21.09.2018 - 01:08
fonte
1

In breve

I ascoltatori sono molto vicini a osservatori . Tuttavia, sembrano essere strettamente accoppiati a un soggetto osservato molto specifico (ad esempio Currency ). Di conseguenza, l'ascolto di altri tipi di soggetti richiederebbe ulteriori interfacce di ascolto e l'implementazione aggiuntiva di metodi di dispiegamento simili.

Il pattern observer originale, al contrario, assicura la riusabilità e l'estendibilità fornendo un accoppiamento astratto tra il soggetto osservato (di seguito osservabile ) e gli osservatori . Ciò consente a ciascun lato del modello di essere ulteriormente specializzato in modo indipendente.

In conclusione, i ascoltatori non sono abbastanza osservatori .

A lungo, con molti dettagli

Il tuo design

Comprendo il seguente disegno:

  • I tuoi ascoltatori concreti implementano tutti l'interfaccia CurrencyListener con un metodo specifico CurrencyListener.currencyUpdated(Currency currency) .
  • Hai altre interfacce listener per altri tipi di aggiornamenti con altre implementazioni.
  • Il mittente della notifica contiene un elenco di CurrencyListener ,
  • Il mittente della notifica esegue iterazioni su questo elenco e attiva i loro metodi currencyUpdated() .

Problemi aperti:

  • Non dici come aggiungi / rimuovi i listener al mittente della notifica. Non è una domanda importante qui, ma lo schema dell'osservatore potrebbe ispirarti su questo punto.
  • Non si indica se lo stato del mittente della notifica è utilizzato dal listener (tipico per un osservatore) o se la valuta è l'oggetto che l'ascoltatore ascolta (variante tipica del pattern dell'osservatore, utilizzato quando lo stesso osservatore deve guardare più osservabili). Di seguito, assumerò quest'ultimo.

Mappatura del progetto con il modello di osservatore

Il confronto tra il tuo design e il modello di progettazione degli osservatori suggerisce che:

  • Il mittente della notifica è un Observable (a meno che Currency sia)
  • L'elenco di listener è una raccolta di Observer
  • Il CurrencyListener è un'interfaccia Observer
  • Il metodo CurrencyUpdated() è un metodo update()
  • Gli ascoltatori concreti sono concreti Observer

Qual è la differenza?

  • Il mittente della notifica e la valuta non sono un'interfaccia astratta ma è una classe concreta. Non sembrano neanche una classe generale che offre un'interfaccia che sarebbe abbastanza astratta. Ciò significa che i tuoi osservatori dipendono tutti da quella classe concreta (strong accoppiamento invece di accoppiamento astratto).
  • Il pattern Observer ha un meccanismo di registrazione per aggiungere / rimuovere osservatori ad un osservabile. (Ma forse lo hai anche tu ma non l'hai detto?)
  • La tua CurrencyListener impone il tipo concreto di oggetto che riceverà la funzione di aggiornamento. E questo tipo sembra essere molto specifico e strettamente legato al mittente della notifica. Quindi implementare gli ascoltatori per un nuovo tipo di osservabili richiede ogni volta una nuova interfaccia.
  • Al contrario, Observer.update() non ha bisogno di conoscere il concreto Observable . Ciò consente di disaccoppiare le implementazioni. Il concreto Observer conosce il concreto Observable e può ottenere il suo stato. Una variante conosciuta è Observer.update(Observable o) . Quindi gli osservatori rimangono disaccoppiati da un'attuazione (troppo) concreta dell'osservabile.

Conclusioni:

I tuoi ascoltatori stanno bene. Se tu avessi solo un tipo di soggetti osservabili, potrebbero addirittura semplificare il design.

Ma rifattorizzarli usando il modello di osservatore può aiutare a disaccoppiare le parti, il che potrebbe facilitare il riutilizzo e migliorare la flessibilità.

    
risposta data 21.09.2018 - 00:16
fonte

Leggi altre domande sui tag