Observer (Design Pattern): Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K
 
(10 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt)
Zeile 3: Zeile 3:
 
Das Subjekt aktualisiert die Beobachter unter Verwendung eines öffentlichen Protokolls, das für alle Beobachter gilt. Beispiel:
 
Das Subjekt aktualisiert die Beobachter unter Verwendung eines öffentlichen Protokolls, das für alle Beobachter gilt. Beispiel:
  
<code=java>
+
<syntaxhighlight lang="java">
 
     package observer;
 
     package observer;
  
Zeile 10: Zeile 10:
  
 
       /**
 
       /**
         * Diese Methode wird aufgerufen, wenn das beobachtete Objekt verändert wird.
+
         * Diese Methode wird aufgerufen, wenn dadas Subjekt verändert wird.
 
         * Die Anwendung ruft die Subjekt-Methode notifyObservers auf
 
         * Die Anwendung ruft die Subjekt-Methode notifyObservers auf
         * um allen Beobachtern mitzuteilen, dass das beobachtete Objekt geändert wurde.
+
         * um allen Beobachtern mitzuteilen, dass das Subjekt geändert wurde.
 
         */
 
         */
 
       public void update(Subject s);
 
       public void update(Subject s);
 
     }
 
     }
</code=java>
+
</syntaxhighlight>
  
 
Beobachter sind lose mit dem Subjekt verbunden ist, weil das Subjekt nichts über die Beobachter weiß, außer dass sie das "Observer"-Protokoll verwirklichen.
 
Beobachter sind lose mit dem Subjekt verbunden ist, weil das Subjekt nichts über die Beobachter weiß, außer dass sie das "Observer"-Protokoll verwirklichen.
Zeile 22: Zeile 22:
 
Ein Objekt kann sich als ein Beobachter bei einem oder mehreren Subjekten anmelden, indem es ebenfalls ein öffentliches Protokoll benutzt, das für alle Subjekte gilt. Beispiel:
 
Ein Objekt kann sich als ein Beobachter bei einem oder mehreren Subjekten anmelden, indem es ebenfalls ein öffentliches Protokoll benutzt, das für alle Subjekte gilt. Beispiel:
  
<code=java>
+
<syntaxhighlight lang="java">
 
     package observer;
 
     package observer;
  
Zeile 30: Zeile 30:
 
       /**
 
       /**
 
         * Füge einen Beobachter zu der Liste der Beobachter dieses Objekts hinzu,
 
         * Füge einen Beobachter zu der Liste der Beobachter dieses Objekts hinzu,
         * sofern der Beobachter nicht bereits in der Liste ist.
+
         * sofern der Beobachter nicht bereits in der Liste vorhanden ist.
 
         */
 
         */
 
       public void addObserver(Observer o);
 
       public void addObserver(Observer o);
Zeile 44: Zeile 44:
 
       public void notifyObservers();
 
       public void notifyObservers();
 
     }
 
     }
</code=java>
+
</syntaxhighlight>
  
 
Die Reihenfolge, in der Beobachter von der Subjekt-Methode "notifyObservers" informiert werden, wird in der Regel nicht definiert, auch sollte die Anwendung sich nicht auf eine bestimmte Reihenfolge verlassen.
 
Die Reihenfolge, in der Beobachter von der Subjekt-Methode "notifyObservers" informiert werden, wird in der Regel nicht definiert, auch sollte die Anwendung sich nicht auf eine bestimmte Reihenfolge verlassen.
Zeile 52: Zeile 52:
 
Hier ist ein Beispiel eines Beobachters und eines Subjekts, sowie einer Klasse zum Starten der Anwendung. Kurze Zusammenfassung der Anwendung: eine Nachrichtenagentur beginnt Nachrichten zu veröffentlichen. Man kann sich bei einer Agentur abonnieren und immer, wenn eine neue Nachricht veröffentlicht wurde, wird man darüber informiert. Man kann auch das Abonnement kündigen, wenn man nicht mehr benachrichtigt werden möchte. Die Personen, die sich abonnieren können, werden durch die Klasse "Reader" definiert (der Beobachter), und die Agentur durch die Klasse "NewsPublisher" (das Subjekt, der Beobachtbare oder Observable):
 
Hier ist ein Beispiel eines Beobachters und eines Subjekts, sowie einer Klasse zum Starten der Anwendung. Kurze Zusammenfassung der Anwendung: eine Nachrichtenagentur beginnt Nachrichten zu veröffentlichen. Man kann sich bei einer Agentur abonnieren und immer, wenn eine neue Nachricht veröffentlicht wurde, wird man darüber informiert. Man kann auch das Abonnement kündigen, wenn man nicht mehr benachrichtigt werden möchte. Die Personen, die sich abonnieren können, werden durch die Klasse "Reader" definiert (der Beobachter), und die Agentur durch die Klasse "NewsPublisher" (das Subjekt, der Beobachtbare oder Observable):
  
<code=java>
+
<syntaxhighlight lang="java">
 
     package observer;
 
     package observer;
  
Zeile 69: Zeile 69:
 
       public void update(final Subject s)
 
       public void update(final Subject s)
 
       {
 
       {
           if (s instanceof NewsPublisher)
+
           NewsPublisher newsPublisher = (NewsPublisher) s;
          {
+
          String news = newsPublisher.getNews();
            NewsPublisher newsPublisher = (NewsPublisher) s;
+
          System.out.println("'" + name + "' hat diese Nachricht erhalten: '" + news + "'");
            String news = newsPublisher.getNews();
 
            System.out.println("'" + name + "' hat diese Nachricht erhalten: '" + news + "'");
 
          }
 
 
       }
 
       }
  
Zeile 87: Zeile 84:
 
       }
 
       }
 
     }
 
     }
</code=java>
+
</syntaxhighlight>
  
<code=java>
+
<syntaxhighlight lang="java">
 
     package observer;
 
     package observer;
  
Zeile 99: Zeile 96:
  
 
       private String news;
 
       private String news;
       private List observersList;
+
       private List<Observer> observersList;
  
 
       public NewsPublisher()
 
       public NewsPublisher()
 
       {
 
       {
           observersList = new ArrayList(10);
+
           observersList = new ArrayList<>();
 
       }
 
       }
  
Zeile 124: Zeile 121:
 
       public void notifyObservers()
 
       public void notifyObservers()
 
       {
 
       {
           for (int i = 0; i < observersList.size(); i++)
+
           for (Observer observer : observersList)
 
           {
 
           {
            Observer observer = (Observer) observersList.get(i);
 
 
             observer.update(this);
 
             observer.update(this);
 
           }
 
           }
Zeile 152: Zeile 148:
 
     }
 
     }
  
</code=java>
+
</syntaxhighlight>
  
<code=java>
+
<syntaxhighlight lang="java">
 
     package observer;
 
     package observer;
  
Zeile 176: Zeile 172:
 
       }
 
       }
 
     }
 
     }
</code=java>
+
</syntaxhighlight>
  
 
Die Anwendung gibt dies auf der Konsole aus:
 
Die Anwendung gibt dies auf der Konsole aus:
Zeile 186: Zeile 182:
 
Beachten wir, dass Philip (im Gegensatz zu Franz) nicht die Information erhalten hat 'Pierre reist nach Deutschland.', weil er sein Abonnement vor der Veröffentlichung der Meldung kündigte:
 
Beachten wir, dass Philip (im Gegensatz zu Franz) nicht die Information erhalten hat 'Pierre reist nach Deutschland.', weil er sein Abonnement vor der Veröffentlichung der Meldung kündigte:
  
<code=java>
+
<syntaxhighlight lang="java">
 
     reader2.unsubscribe (newsPublisher);
 
     reader2.unsubscribe (newsPublisher);
</code=java>
+
</syntaxhighlight>
  
Ab diesem Zeitpunkt wurde Philip aus der Liste der Beobachter des Objekts "newsPublisher" entfernt und er wird nicht mehr benachrichtigt, bis er sich wieder abonniert.
+
Ab diesem Zeitpunkt wurde Philip aus der Liste der Beobachter des Objekts "newsPublisher" entfernt und er wird nicht mehr benachrichtigt, bis er wieder abonniert.
  
[[Kategorie:Java]]
 
 
[[Kategorie:Design Pattern]]
 
[[Kategorie:Design Pattern]]
 +
[[Kategorie:Design Patterns]]
 
[[Kategorie:Gang of Four Pattern]]
 
[[Kategorie:Gang of Four Pattern]]

Aktuelle Version vom 19. Januar 2019, 14:41 Uhr

Das Observer Design Pattern definiert eine Abhängigkeit zwischen einem Subjekt (auch bekannt als "der Beobachtbare" oder "Observable") und mehreren Beobachtern, so dass, wenn das Subjekt seinen Zustand ändert, alle seine abhängigen Objekte (seine Beobachter) automatisch benachrichtigt und aktualisiert werden.

Das Subjekt aktualisiert die Beobachter unter Verwendung eines öffentlichen Protokolls, das für alle Beobachter gilt. Beispiel:

    package observer;

    public interface Observer
    {

       /**
        * Diese Methode wird aufgerufen, wenn dadas Subjekt verändert wird.
        * Die Anwendung ruft die Subjekt-Methode notifyObservers auf
        * um allen Beobachtern mitzuteilen, dass das Subjekt geändert wurde.
        */
       public void update(Subject s);
    }

Beobachter sind lose mit dem Subjekt verbunden ist, weil das Subjekt nichts über die Beobachter weiß, außer dass sie das "Observer"-Protokoll verwirklichen.

Ein Objekt kann sich als ein Beobachter bei einem oder mehreren Subjekten anmelden, indem es ebenfalls ein öffentliches Protokoll benutzt, das für alle Subjekte gilt. Beispiel:

    package observer;

    public interface Subject
    {

       /**
        * Füge einen Beobachter zu der Liste der Beobachter dieses Objekts hinzu,
        * sofern der Beobachter nicht bereits in der Liste vorhanden ist.
        */
       public void addObserver(Observer o);

       /**
        * Entferne einen Beobachter aus der Liste der Beobachter dieses Objekts.
        */
       public void deleteObserver(Observer o);

       /**
        * Informiere alle Beobachter, dass dieses Objekt modifiziert wurde.
        */
       public void notifyObservers();
    }

Die Reihenfolge, in der Beobachter von der Subjekt-Methode "notifyObservers" informiert werden, wird in der Regel nicht definiert, auch sollte die Anwendung sich nicht auf eine bestimmte Reihenfolge verlassen.

Für ein Subjekt ist es wichtig, die Beobachter nur dann zu benachrichtigen, wenn sich wirklich etwas verändert hat, sonst kann es zu einer endlosen Kette von Meldungen kommen, auch wenn sich nichts geändert hat.

Hier ist ein Beispiel eines Beobachters und eines Subjekts, sowie einer Klasse zum Starten der Anwendung. Kurze Zusammenfassung der Anwendung: eine Nachrichtenagentur beginnt Nachrichten zu veröffentlichen. Man kann sich bei einer Agentur abonnieren und immer, wenn eine neue Nachricht veröffentlicht wurde, wird man darüber informiert. Man kann auch das Abonnement kündigen, wenn man nicht mehr benachrichtigt werden möchte. Die Personen, die sich abonnieren können, werden durch die Klasse "Reader" definiert (der Beobachter), und die Agentur durch die Klasse "NewsPublisher" (das Subjekt, der Beobachtbare oder Observable):

    package observer;

    public class Reader implements Observer
    {

       private final String name;

       public Reader(final String name)
       {
          this.name = name;

       }

       @Override
       public void update(final Subject s)
       {
          NewsPublisher newsPublisher = (NewsPublisher) s;
          String news = newsPublisher.getNews();
          System.out.println("'" + name + "' hat diese Nachricht erhalten: '" + news + "'");
       }

       public void subscribe(final Subject s)
       {
          s.addObserver(this);
       }

       public void unsubscribe(final Subject s)
       {
          s.deleteObserver(this);
       }
    }
    package observer;

    import java.util.ArrayList;
    import java.util.List;

    public class NewsPublisher implements Subject
    {

       private String news;
       private List<Observer> observersList;

       public NewsPublisher()
       {
          observersList = new ArrayList<>();
       }

       @Override
       public void addObserver(final Observer observer)
       {
          if (!observersList.contains(observer))
          {
             observersList.add(observer);
          }
       }

       @Override
       public void deleteObserver(final Observer observer)
       {
          observersList.remove(observer);
       }

       @Override
       public void notifyObservers()
       {
          for (Observer observer : observersList)
          {
             observer.update(this);
          }
       }

       public String getNews()
       {
          return news;
       }

       public void setNews(final String news)
       {
          // Zuerst überprüfen wir, ob der Wert des "news"-Parameters
          // verschieden ist von dem Wert der Eigenschaft "news".
          if (this.news == null && news == null)
          {
             return;
          }
          if (this.news == null || !this.news.equals(news))
          {
             this.news = news; //das Objekt wird verändert, ...
             notifyObservers(); //wir müssen also alle Beobachter darüber informieren!
          }
       }
    }
    package observer;

    public class Demo
    {

       public static void main(final String[] args)
       {
          NewsPublisher newsPublisher = new NewsPublisher();

          Reader reader1 = new Reader("Franz");
          reader1.subscribe(newsPublisher);

          Reader reader2 = new Reader("Philip");
          reader2.subscribe(newsPublisher);

          newsPublisher.setNews("Paul hat ein neues Auto gekauft.");

          reader2.unsubscribe(newsPublisher);
          newsPublisher.setNews("Pierre reist nach Deutschland.");
       }
    }

Die Anwendung gibt dies auf der Konsole aus:

  • 'Franz' hat diese Informationen erhalten: 'Paul hat ein neues Auto gekauft.'
  • 'Philip' hat diese Informationen erhalten: 'Paul hat ein neues Auto gekauft.'
  • 'Franz' hat diese Informationen erhalten: 'Pierre reist nach Deutschland.'

Beachten wir, dass Philip (im Gegensatz zu Franz) nicht die Information erhalten hat 'Pierre reist nach Deutschland.', weil er sein Abonnement vor der Veröffentlichung der Meldung kündigte:

    reader2.unsubscribe (newsPublisher);

Ab diesem Zeitpunkt wurde Philip aus der Liste der Beobachter des Objekts "newsPublisher" entfernt und er wird nicht mehr benachrichtigt, bis er wieder abonniert.