Pattern osservatore e riferimenti circolari

4

Stavo controllando questo esempio di Pattern Observer.

link

Sembra che ci sia un riferimento circolare quando si usa il Pattern di Osservatore.

import java.util.ArrayList;
import java.util.List;
public class Subject {

   private List<Observer> observers = new ArrayList<Observer>();
   private int state;

   public int getState() {
      return state;
   }

   public void setState(int state) {
      this.state = state;
      notifyAllObservers();
   }

   public void attach(Observer observer){
      observers.add(observer);      
   }

   public void notifyAllObservers(){
      for (Observer observer : observers) {
         observer.update();
      }
   }    
}


public class BinaryObserver extends Observer{

  public BinaryObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Binary String: " + Integer.toBinaryString( subject.getState() ) ); 
   }
}

Non sto pubblicando tutti gli altri codici, ma dall'aspetto iniziale sembra che tale design abbia quasi sempre un riferimento circolare. Sto fraintendendo qualcosa qui?

Grazie,

    
posta hagubear 19.12.2018 - 11:34
fonte

3 risposte

2

Sì, hai ragione. Entrambi gli oggetti si conoscono se questo è ciò a cui ti stai riferendo. La cosa importante è cosa conoscono l'uno dell'altro. Mentre BinaryObserver conosce il Subject in dettaglio, Subject conosce solo Observers . Per essere più precisi, Subject non conosce i dettagli sulla tua BinaryObserver , può solo inviare messaggi che sono definiti nella classe Observer . In questo modo Subject è disaccoppiato dai dettagli della tua classe BinaryObserver .

Per riassumere, mentre l'accoppiamento di BinaryObserver con Subject è molto alto, l'accoppiamento nella direzione opposta è debole.

    
risposta data 19.12.2018 - 12:14
fonte
1

Puoi evitare il riferimento circolare con una leggera modifica all'interfaccia Observer:

interface Observer {
  void update(Subject subject);
}

Il notifyAll diventa:

public void notifyAllObservers(){
  for (Observer observer : observers) {
     observer.update(this);
  }
}

Ci sono potenzialmente alcuni compromessi, ma nell'esempio che hai mostrato, ti servirebbe un solo oggetto Observer per tutti i Soggetti nell'applicazione. Se lo fai come mostra il tutorial, ne hai bisogno uno per ogni soggetto. Si tratta di un sacco di oggetti extra in giro solo per tenere traccia di un riferimento che è facilmente passato.

Un altro problema con il pattern Observable è che si può finire con perdite di memoria perché l'oggetto osservato contiene riferimenti agli osservatori. Di solito il modello include un metodo di rimozione, ma considera l'utilizzo di WeakReference per consentire agli oggetti di interrompere automaticamente l'ascolto quando non rientrano nell'ambito di applicazione.

    
risposta data 19.12.2018 - 16:02
fonte
1

Aggiornamento: come sottolineato da JimmyJames nei commenti, la domanda riguarda i riferimenti circolari e non le dipendenze

circolari

Risposta originale, dove pensavo stessimo discutendo delle dipendenze circolari:

In realtà, a causa del polimorfismo, non vi è alcuna dipendenza circolare qui. Diamo un'occhiata più da vicino alle dipendenze per capire perché:

  • BinaryObserver dipende da Subject e Observer
  • Subject dipende da Observer
  • Observer non ha alcuna dipendenza.

Poiché Subject dipende dall'interfaccia Observer piuttosto che da qualsiasi implementazione concreta, il principio di inversione delle dipendenze viene seguito. Questo principio afferma:

  1. I moduli di alto livello non dovrebbero dipendere da moduli di basso livello. Entrambi dovrebbero dipendere dalle astrazioni.
  2. Le astrazioni non dovrebbero dipendere dai dettagli. I dettagli dovrebbero dipendere dalle astrazioni.

Quindi, anche se può sembrare una dipendenza circolare a colpo d'occhio, in realtà è solo una polimorfizzazione di un'implementazione concreta che dipende da Subject ( BinaryObserver ) verso un'interfaccia senza dipendenza Subject ( Observer ), e iniettare quell'oggetto polimorfo nel costruttore di Subject . Quindi, nessuna dipendenza circolare.

    
risposta data 19.12.2018 - 18:27
fonte

Leggi altre domande sui tag