Observer Pattern

Die Definition dieses Patterns lautet:

„Definiere eine 1-zu-n-Abhängigkeit zwischen Objekten, so dass die Änderung des
Zustands eines Objekts dazu führt, dass alle abhängigen Objekte benachrichtigt
und automatisch aktualisiert werden.“

Stellen sie sich eine Party vor. Auf dieser Party gibt es 2 Gruppen von Gästen. Die einen die aktiv Erzählen und die anderen die passiv zuhören. Die Erzähler (Observable) interessiert es nicht wer ihnen zuhört, sie schweigen aber wenn sie gar keinen Zuhörer (Observer) haben. Die Zuhörer reagieren auf Witze der Unterhalter.

Realisierung

Um einen Erzähler zu realisieren bietet sich die Klasse Observable an. Diese verfügt über die beiden Methoden setChanged() und notifyObservers(). Mit setChanged() wird die Änderung angekündigt, und mit notifyObservers() wird sie tatsächlich übermittelt.

Würde es keine Änderungen geben, würde notifyObservers auch nichts übertragen.

Wir stellen jetzt unser Party-Szenario nach. Zuerst schreiben wir eine Klasse namens JokeTeller. Die erstellten Objekte erzählen einen Witz und verschicken sie an alle Zuhörer.

class JokeTeller extends Observable{
  private static final List() jokes = Arrays.asList(
    "Sorry, aber du siehst so aus, wie ich mich fühle.",
    "Eine Null kann ein bestehendes Problem verzehnfachen.",
    "Wer zuletzt lacht, hat es nicht eher begriffen.",
    "Wer zuletzt lacht, stirbt wenigstens fröhlich.",
    "Unsere Luft hat einen Vorteil: Man sieht, was man einatmet."
  );

  public void tellJoke(){
    setChanged();
    Collections.shuffle( jokes );
    notifyObservers( jokes.get(0) );
  }
}

setChanged() setzt intern eine Flag. Nach dem Aufruf der notifyObservers() Methode wird diese wieder gelöscht.

Interessierte Zuhörer (Beobachter) müssen sich am Observable-Objekt mit der Methode addObserver anmelden. Gültige Objekte sind aber nur jene, welche die Schnittstelle Observer implementieren. Mit der Methode deleteObserver(Observer) können sie sich wieder abmelden.

Die Namensgebung der Oberklasse ist leider etwas unglücklich gewählt. Normalerweise drückt „able“ immer ein Schnittstelle aus. In diesen Fall ist aber Observable eine echte Klasse während Observer eine Schnittstelle bezeichnet.

Die Observer Schnittstelle

Als nächstes folgt die Realisierung der Zuhörer Klasse. Die hat die Schnittstelle Observer implementiert. Ihre Aufgabe besteht darin auf die Witze des Erzählers zu reagieren. Als Attribute besitzt es nur einen Namen.

class JokeListener implements Observer{
  final private String name;

  JokeListener( String name ){
    this.name = name;
  }

  @Override public void update( Observable o, Object arg ){
    System.out.println( name + " lacht über: \"" + arg + "\"" );
  }
}

Die Party kann beginnen

Um unser Beispiel zu beenden erstellen wir jetzt eine Party Klasse und lassen unser Partygäste miteinander agieren.


public class Party
{
  public static void main( String[] args )
  {
    Observer achim    = new JokeListener( "Achim" );
    Observer michael  = new JokeListener( "Michael" );
    JokeTeller chris  = new JokeTeller();

    chris.addObserver( achim );

    chris.tellJoke();
    chris.tellJoke();

    chris.addObserver( michael );

    chris.tellJoke();

    chris.deleteObserver( achim );

    chris.tellJoke();
  }
}

Anwendung

Das Observer Pattern findet sich in fast allen Grafischen Oberflächen wieder. In der Java Welt werden sie als Listener bezeichnet. Besten Beispiel ist ein einfacher Button.

Von Natur aus ist nicht definiert was passieren soll wenn dieser gedrückt wird. Ein EventListener wird an den Button angehängt, der reagieren soll sobald ein bestimmtes Ereignis eintritt. In unseren einfachen Fall wenn der Button betätigt wird.

Zusammenfassung

  • Observer findet immer dann Anwendung, wenn sich der Status eines Objekts ändert und beliebig viele weitere Objeke darüber informiert werden
  • Es gibt Ereignisquellen und Beobachter
  • Beobachter müssen austauschbar sein

Schreibe einen Kommentar