Wann sollten wir Observer und Observable verwenden?

199

Ein Interviewer fragte mich:

Was ist Observerund Observablewann sollen wir sie verwenden?

Ich war diese Bedingungen nicht bewusst, so dass , wenn ich wieder nach Hause und beginne googeln über Observerund Observablefand ich ein paar Punkte aus verschiedenen Quellen an :

1) Observableist eine Klasse und Observereine Schnittstelle.

2) Die ObservableKlasse führt eine Liste von Observers.

3) Wenn ein ObservableObjekt aktualisiert wird, ruft es die update()Methode jedes seiner Objekte Observerauf, um zu benachrichtigen, dass es geändert wurde.

Ich habe dieses Beispiel gefunden:

import java.util.Observable;
import java.util.Observer;

class MessageBoard extends Observable
{
    public void changeMessage(String message) 
    {
        setChanged();
        notifyObservers(message);
    }
}

class Student implements Observer 
{
    @Override
    public void update(Observable o, Object arg) 
    {
        System.out.println("Message board changed: " + arg);
    }
}

public class MessageBoardTest 
{
    public static void main(String[] args) 
    {
        MessageBoard board = new MessageBoard();
        Student bob = new Student();
        Student joe = new Student();
        board.addObserver(bob);
        board.addObserver(joe);
        board.changeMessage("More Homework!");
    }
}

Aber ich verstehe nicht warum wir brauchen Observerund Observable? Wofür setChanged()und notifyObservers(message)Methoden?

Ravi
quelle
Link funktioniert nicht. @Androider Können Sie einen aktualisierten Link bereitstellen?
Prateek
Wenn Sie Java 6 oder höher verwenden, versuchen Sie es mit dzone.com/articles/java-ee6-events-lightweight
Ramiz Uddin
1
Ich würde dringend empfehlen, dieses Buch zu lesen , um ein gutes Verständnis der Entwurfsmuster zu erhalten. Es wirkt albern, ist aber ein hervorragendes Lernwerkzeug.
countofmontecristo
1
Jeder bitte beachten Sie das; Observer / Observable ist in Java 9 veraltet. Alternativen: stackoverflow.com/questions/46380073/…
eren130

Antworten:

264

Sie haben ein konkretes Beispiel für einen Schüler und ein MessageBoard. Der Schüler registriert sich, indem er sich zur Liste der Beobachter hinzufügt, die benachrichtigt werden möchten, wenn eine neue Nachricht an das MessageBoard gesendet wird. Wenn eine Nachricht zum MessageBoard hinzugefügt wird, durchläuft sie die Liste der Beobachter und benachrichtigt sie, dass das Ereignis aufgetreten ist.

Denken Sie an Twitter. Wenn Sie sagen, dass Sie jemandem folgen möchten, fügt Twitter Sie seiner Follower-Liste hinzu. Wenn sie einen neuen Tweet gesendet haben, sehen Sie ihn in Ihrer Eingabe. In diesem Fall ist Ihr Twitter-Konto der Beobachter und die Person, der Sie folgen, die Beobachtbare.

Die Analogie ist möglicherweise nicht perfekt, da Twitter eher ein Mediator ist. Aber es veranschaulicht den Punkt.

Duffymo
quelle
57

In sehr einfachen Worten (da die anderen Antworten Sie ohnehin auf alle offiziellen Entwurfsmuster verweisen, schauen Sie sich diese für weitere Details an):

Wenn Sie eine Klasse haben möchten, die von anderen Klassen im Ökosystem Ihres Programms überwacht wird, möchten Sie, dass die Klasse beobachtbar ist. Das heißt, es gibt möglicherweise einige Änderungen in seinem Status, die Sie an den Rest des Programms senden möchten.

Dazu müssen wir eine Methode aufrufen. Wir möchten nicht, dass die Observable-Klasse eng mit den Klassen verbunden ist, die daran interessiert sind, sie zu beobachten. Es ist egal, wer es ist, solange es bestimmte Kriterien erfüllt. (Stellen Sie sich vor, es ist ein Radiosender, es ist egal, wer zuhört, solange ein UKW-Radio auf seine Frequenz eingestellt ist.) Um dies zu erreichen, verwenden wir eine Schnittstelle, die als Observer bezeichnet wird.

Daher verfügt die Observable-Klasse über eine Liste von Beobachtern (dh Instanzen, die möglicherweise die Observer-Schnittstellenmethoden implementieren). Wann immer es etwas senden möchte, ruft es die Methode einfach nacheinander bei allen Beobachtern auf.

Das Letzte, was das Rätsel schließt, ist, wie die Observable-Klasse weiß, wer interessiert ist. Daher muss die Observable-Klasse einen Mechanismus bieten, mit dem Beobachter ihr Interesse registrieren können. Eine Methode wie z. B. addObserver(Observer o)fügt den Beobachter intern zur Liste der Beobachter hinzu, sodass er, wenn etwas Wichtiges passiert, die Liste durchläuft und die entsprechende Benachrichtigungsmethode der Beobachterschnittstelle jeder Instanz in der Liste aufruft.

Es könnte sein, dass sie Sie im Interview nicht explizit nach dem java.util.Observerund gefragt haben, java.util.Observablesondern nach dem generischen Konzept. Das Konzept ist ein Entwurfsmuster, das Java direkt nach dem Auspacken unterstützt, damit Sie es bei Bedarf schnell implementieren können. Daher würde ich vorschlagen, dass Sie das Konzept und nicht die tatsächlichen Methoden / Klassen verstehen (die Sie bei Bedarf nachschlagen können).

AKTUALISIEREN

Als Antwort auf Ihren Kommentar bietet die eigentliche java.util.ObservableKlasse die folgenden Einrichtungen:

  1. Verwalten einer Liste von java.util.ObserverInstanzen. Neue Instanzen, die benachrichtigt werden möchten, können durch hinzugefügt addObserver(Observer o)und durch entfernt werden deleteObserver(Observer o).

  2. Beibehalten eines internen Status, Angabe, ob sich das Objekt seit der letzten Benachrichtigung an die Beobachter geändert hat. Dies ist nützlich, da es den Teil, in dem Sie sagen, dass sich der Observablegeändert hat, von dem Teil trennt , in dem Sie die Änderungen benachrichtigen. (ZB ist es nützlich, wenn mehrere Änderungen vorgenommen werden und Sie nur am Ende des Prozesses und nicht bei jedem kleinen Schritt benachrichtigen möchten.) Dies geschieht durch setChanged(). Also nennst du es einfach, wenn du etwas in das geändert hast Observableund du willst, dass der Rest Observersirgendwann davon erfährt.

  3. Benachrichtigung aller Beobachter, dass sich der ObservableStatus geändert hat. Dies geschieht durch notifyObservers(). Dies prüft, ob sich das Objekt tatsächlich geändert hat (dh ein Anruf setChanged()wurde getätigt), bevor mit der Benachrichtigung fortgefahren wird. Es gibt zwei Versionen, eine ohne Argumente und eine mit ObjectArgument, falls Sie zusätzliche Informationen mit der Benachrichtigung übergeben möchten. Intern passiert, dass es nur die Liste der ObserverInstanzen durchläuft und die update(Observable o, Object arg)Methode für jede von ihnen aufruft . Hier Observererfahren Sie, welches Objekt sich geändert hat (möglicherweise haben Sie mehr als eines beobachtet), und welches zusätzliche Objekt Object argmöglicherweise zusätzliche Informationen enthält (übergeben) notifyObservers().

jbx
quelle
37

Definition

Das Beobachtermuster wird verwendet, wenn zwischen Objekten eine zu viele Beziehungen bestehen, z. B. wenn ein Objekt geändert wird, seine abhängigen Objekte automatisch benachrichtigt werden und entsprechende Änderungen an allen abhängigen Objekten vorgenommen werden.

Beispiele

  1. Angenommen, Ihre permanente Adresse wird geändert, und Sie müssen die Pass- und Pan-Card-Autorität benachrichtigen. Hier sind also die Passbehörde und die Pan-Card-Behörde Beobachter, und Sie sind ein Subjekt.

  2. Auch auf Facebook werden Sie benachrichtigt, wenn Sie jemanden abonnieren, wenn neue Updates stattfinden.

Wann man es benutzt:

  1. Wenn ein Objekt seinen Status ändert, müssen alle anderen abhängigen Objekte automatisch ihren Status ändern, um die Konsistenz aufrechtzuerhalten

  2. Wenn das Subjekt nicht weiß, wie viele Beobachter es hat.

  3. Wenn ein Objekt in der Lage sein sollte, andere Objekte zu benachrichtigen, ohne zu wissen, wer Objekte sind.

Schritt 1

Betreffklasse erstellen.

Subject.java

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

}}

Schritt 2

Observer-Klasse erstellen.

Observer.java

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

Schritt 3

Erstellen Sie konkrete Beobachterklassen

BinaryObserver.java

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

}}

OctalObserver.java

public class OctalObserver extends Observer{

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

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

}}

HexaObserver.java

public class HexaObserver extends Observer{

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

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

}}

Schritt 4

Verwenden Sie Subjekt- und konkrete Beobachterobjekte.

ObserverPatternDemo.java

 public class ObserverPatternDemo {
    public static void main(String[] args) {
       Subject subject = new Subject();

       new HexaObserver(subject);
       new OctalObserver(subject);
       new BinaryObserver(subject);

       System.out.println("First state change: 15");    
       subject.setState(15);
       System.out.println("Second state change: 10");   
       subject.setState(10);
 }

}}

Schritt 5

Überprüfen Sie die Ausgabe.

Erster Zustandswechsel: 15

Hex String: F.

Oktalzeichenfolge: 17

Binäre Zeichenfolge: 1111

Zweite Zustandsänderung: 10

Hex String: A.

Oktalzeichenfolge: 12

Binäre Zeichenfolge: 1010

Mubarak
quelle
schön erklärt :)
Roottraveller
3
Ich denke, "Definition" ist ein Tippfehler. Ich hoffe es ist ein Tippfehler.
JohnJohn
10

Sie sind Teile des Observer-Entwurfsmusters . Normalerweise werden ein oder mehrere Obervers über Änderungen in einem Observable informiert . Es ist eine Benachrichtigung, dass "etwas" passiert ist, wo Sie als Programmierer definieren können, was "etwas" bedeutet.

Wenn Sie dieses Muster verwenden, entkoppeln Sie beide Entitäten voneinander - die Beobachter werden steckbar.

Andy
quelle
Ich werde es begrüßen, wenn Sie die Erklärung von board.changeMessage("More Homework!");in Ihrer Antwort hinzufügen , ich meine, was passiert, wenn changeMessage("More Homework!");aufgerufen.
Ravi
9

Observer aka Callback ist bei Observable registriert.

Es wird verwendet, um z. B. über Ereignisse zu informieren, die zu einem bestimmten Zeitpunkt aufgetreten sind. Es wird in Swing, Ajax, GWT häufig zum Versenden von Vorgängen für z. B. UI-Ereignisse (Schaltflächenklicks, geänderte Textfelder usw.) verwendet.

In Swing finden Sie Methoden wie addXXXListener (Listener l), in GWT haben Sie (Async) Rückrufe.

Da die Liste der Beobachter dynamisch ist, können sich Beobachter zur Laufzeit registrieren und die Registrierung aufheben. Es ist auch eine gute Möglichkeit, beobachtbare Elemente von Beobachtern zu entkoppeln, da Schnittstellen verwendet werden.

Pawel Solarski
quelle
9

Wenn der Interviewer nach der Implementierung des Observer-Entwurfsmusters fragt ohne Verwendung von Observer-Klassen und -Schnittstellen anfordert, können Sie das folgende einfache Beispiel verwenden!

MyObserver als Beobachterschnittstelle

interface MyObserver {

    void update(MyObservable o, Object arg);
}

MyObservable als Observable-Klasse

class MyObservable
{
    ArrayList<MyObserver> myObserverList = new ArrayList<MyObserver>();

    boolean changeFlag = false;

    public void notifyObservers(Object o)
    {
        if (hasChanged())
        {
            for(MyObserver mo : myObserverList) {
                mo.update(this, o);
            }
            clearChanged();
        }
    }


    public void addObserver(MyObserver o) {
        myObserverList.add(o);        
    }

    public void setChanged() {
        changeFlag = true;
    }

    public boolean hasChanged() {
        return changeFlag;
    }

    protected void clearChanged() {
        changeFlag = false;
    }

    // ...
}

Ihr Beispiel mit MyObserver und MyObservable!

class MessageBoard extends MyObservable {
  private String message;

  public String getMessage() {
    return message;
  }

  public void changeMessage(String message) {
    this.message = message;
    setChanged();
    notifyObservers(message);
  }

  public static void main(String[] args) {
    MessageBoard board = new MessageBoard();
    Student bob = new Student();
    Student joe = new Student();
    board.addObserver(bob);
    board.addObserver(joe);
    board.changeMessage("More Homework!");
  }
}

class Student implements MyObserver {

  @Override
  public void update(MyObservable o, Object arg) {
    System.out.println("Message board changed: " + arg);
  }

}
Habeeb Perwad
quelle
5

"Ich habe versucht herauszufinden, warum genau wir Observer und Observable brauchen."

Wie bereits in früheren Antworten erwähnt, bieten sie die Möglichkeit, einen Beobachter zu abonnieren, um automatische Benachrichtigungen über ein beobachtbares Objekt zu erhalten.

Eine Beispielanwendung, bei der dies nützlich sein kann, ist die Datenbindung wir an, Sie haben eine Benutzeroberfläche, die einige Daten bearbeitet, und Sie möchten, dass die Benutzeroberfläche reagiert, wenn die Daten aktualisiert werden. Sie können Ihre Daten beobachtbar machen und Ihre Benutzeroberflächenkomponenten abonnieren die Daten

Knockout.js ist ein MVVM-Javascript-Framework mit einem großartigen Tutorial für den Einstieg. Um mehr Observables in Aktion zu sehen, empfehle ich wirklich, das Tutorial durchzuarbeiten. http://learn.knockoutjs.com/

Ich habe diesen Artikel auch auf der Startseite von Visual Studio 2008 gefunden ( Das Observer-Muster ist die Grundlage für die Entwicklung von Model View Controller (MVC) ). Http://visualstudiomagazine.com/articles/2013/08/14/the-observer-pattern-in -net.aspx

Eduardo Wada
quelle
3

Ich habe hier eine kurze Beschreibung des Beobachtermusters geschrieben: http://www.devcodenote.com/2015/04/design-patterns-observer-pattern.html

Ein Ausschnitt aus der Post:

Beobachtermuster: Es stellt im Wesentlichen eine Eins-zu-Viele-Beziehung zwischen Objekten her und hat ein lose gekoppeltes Design zwischen voneinander abhängigen Objekten.

TextBook-Definition: Das Observer-Muster definiert eine Eins-zu-Viele-Abhängigkeit zwischen Objekten, sodass alle abhängigen Objekte automatisch benachrichtigt und aktualisiert werden, wenn ein Objekt seinen Status ändert.

Betrachten Sie beispielsweise einen Feed-Benachrichtigungsdienst. Abonnementmodelle sind am besten geeignet, um das Beobachtermuster zu verstehen.

Abhishek Jain
quelle
0

Das Beobachtermuster wird verwendet, wenn zwischen Objekten eine Eins-zu-Viele-Beziehung besteht, z. B. wenn ein Objekt geändert wird, müssen seine abhängigen Objekte automatisch benachrichtigt werden.

Swapnil Sharma
quelle