Bei einem Beobachter handelt es sich um ein Verhaltens-Entwurfsmuster. Ändert sich ein Objekt, informiert es jeden angemeldeten Beobachter über die Änderung.
Anwendungen
Eine oder auch mehrere Komponenten stellen den Status eines Objektes dar. Sie kennen die gesamte Schnittstelle dieses Objektes. Ändert sich der Status des Objektes müssen die Komponenten darüber informiert werden, das Objekt soll aber von den Komponenten unabhängig bleiben - ihre Schnittstelle also nicht kennen.
- Beispiel: Messergebnisse werden gleichzeit in einem Balkendiagramm, einem Liniendiagramm und einer Tabelle dargestellt. Messwerte ändern sich permanent. Die Komponenten der Diagramme sollen diese Änderungen permanent darstellen, das gemessene Objekt soll aber keine Kenntnis über die Struktur dieser Komponenten besitzen.
Lösung
Das beobachtete Objekt bietet einen Mechanismus um Beobachter an- und abzumelden und diese über Änderungen zu informieren. Es kennt alle seine Beobachter nur über die (überschaubare) Schnittstelle Beobachter. Es meldet jede Änderung völlig unspezifisch an jeden angemeldeten Beobachter, braucht also die weitere Struktur dieser Komponenten nicht zu kennen.
Die Beobachter implementieren ihrerseits eine (spezifische) Methode, um auf die Änderung zu reagieren. In der Regel werden die für eine Komponente relevanten Teile des Status abgefragt. werqwrqwerwer
Java
interface Beobachtbar { // b wird in die interne Liste der Beobachter aufgenommen public void meldeBeobachterAn(Beobachter b); // b wird aus der internen Liste der Beobachter entfernt public void meldeBeobachterAb(Beobachter b); // Für alle Beobachter der internen Liste wird die Methode "beachteAenderung" aufgerufen // diese Methode wird am Ende jeder verändernden Methode aufgerufen public void meldeAenderung(); }
interface Beobachter { // hier wird konkret implementiert, was eine Änderung für Folgen hat public void beachteAenderung(); }
Der Mechanismus der An- und Abmeldung sowie der Meldung ist völlig allgemein und könnte auch in einer konkreten Oberklasse vollständig implementiert werden. Das beobachtete Objekt würde dann nicht das Interface Beobachtbar implementieren, sondern von der Oberklasse Beobachtbar erben. In Java gibt es allerdings keine Mehrfachvererbung, so dass dieser Ansatz nur anwendbar ist, wenn keine weitere Vererbung vorgesehen ist.
Der Mechanismus der "Änderungsbeachtung" ist anwendungsabhängig und muss in jedem Fall konkret implementiert werden.
Vorteile
- Ein abhängiges Objekt erhält die Änderungen automatisch. Dabei muss das beobachtete Objekt jedoch keine Kenntnis über die Struktur seiner Beobachter besitzen. Der Beobachtete kennt seine Beobachter nur über die Schnittstelle Beobachter. Dies führt zu der gewünschten "Losen Kopplung".
Nachteile
- Änderungen am Objekt führen bei großer Beobachteranzahl zu hohen Änderungskosten. (Das Subjekt informiert jeden Beobachter, auch wenn dieser die Änderungsinformation nicht benötigt.)
- Ruft ein Beobachter während der Bearbeitung einer gemeldeten Änderung wiederum Änderungsmethoden des Subjektes auf, kommt es zu Endlosschleifen.
- Der Mechanismus liefert keine Information darüber, was sich geändert hat. (Die daraus resultierende Unabhängigkeit der Komponenten kann sich auch als Vorteil herausstellen.)
Java bietet fertige Observer und Observableklassen an, die der Entwickler verwenden kann.
Die Nachteile des Entwurfsmusters entfernt Java, indem es das Beobachterkonzept durch Listener und Events ersetzt. Interessiert sich eine Klasse für eine andere, implementiert sie deren Listener-interface und meldet sich beim Subjekt an. Ändert sich das Subjekt, informiert es seine Beobachter durch den Aufruf der Listenerschnittstelle, die die Änderung beschreibt.