Observer-Entwurfsmuster (Observer Pattern)

Aus dev.kaibel.net
Zur Navigation springen Zur Suche springen

Observer-Entwurfsmuster (Observer Pattern)

Das Observer-Entwurfsmuster (deutsch: Beobachter-Muster) ist ein Verhaltensmuster, das verwendet wird, um eine eins-zu-viele-Abhängigkeit zwischen Objekten zu definieren. Wenn sich der Zustand eines Objekts (des Subjects) ändert, werden automatisch alle abhängigen Objekte (die Observer) benachrichtigt und aktualisiert.

Das Muster wird häufig für Ereignisbenachrichtigungen, GUI-Updates oder Echtzeitkommunikation eingesetzt.

Grundidee

Ein Objekt („Subject“) verwaltet eine Liste von Beobachtern („Observer“) und informiert sie, sobald sich sein Zustand ändert. Dadurch wird eine lose Kopplung zwischen Sender und Empfänger erreicht – das Subject kennt seine Observer nicht im Detail.

+-------------------+        +-------------------+
|     Subject       |<------>|     Observer      |
|-------------------|        |-------------------|
| + attach()        |        | + update()        |
| + detach()        |        |                   |
| + notify()        |        +-------------------+
+-------------------+

Struktur

Komponente Beschreibung
Subject Verwaltet eine Liste von Observern und benachrichtigt sie bei Zustandsänderungen.
Observer Definiert ein Interface zur Aktualisierung bei Benachrichtigung.
ConcreteSubject Konkrete Implementierung des Subjects; speichert den Zustand.
ConcreteObserver Beobachtet ein Subject und reagiert auf Benachrichtigungen.

Beispiel (C++)

Ein einfaches Beispiel für das Observer-Muster in C++:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

class Observer {
public:
    virtual void update(const std::string& message) = 0;
    virtual ~Observer() = default;
};

class Subject {
    std::vector<Observer*> observers;
public:
    void attach(Observer* obs) {
        observers.push_back(obs);
    }

    void detach(Observer* obs) {
        observers.erase(std::remove(observers.begin(), observers.end(), obs), observers.end());
    }

    void notify(const std::string& message) {
        for (auto* obs : observers)
            obs->update(message);
    }
};

class ConcreteObserver : public Observer {
    std::string name;
public:
    explicit ConcreteObserver(std::string n) : name(std::move(n)) {}
    void update(const std::string& message) override {
        std::cout << name << " erhielt Nachricht: " << message << std::endl;
    }
};

int main() {
    Subject newsStation;

    ConcreteObserver alice("Alice");
    ConcreteObserver bob("Bob");

    newsStation.attach(&alice);
    newsStation.attach(&bob);

    newsStation.notify("Neue Nachricht: Design Patterns erklärt!");

    newsStation.detach(&bob);
    newsStation.notify("Zweite Nachricht: Nur Alice wird benachrichtigt.");
}

Erklärung

In diesem Beispiel:

  • Das Subject (NewsStation) hält eine Liste von Beobachtern.
  • Bei einer Änderung ruft es notify() auf.
  • Jeder Observer wird mit update() benachrichtigt.

So bleibt das System flexibel: Neue Beobachter können leicht hinzugefügt oder entfernt werden, ohne das Subject zu verändern.

Vorteile

  • Lose Kopplung zwischen Sender (Subject) und Empfänger (Observer)
  • Beliebig viele Empfänger möglich
  • Dynamisches An- und Abmelden der Beobachter

Nachteile

  • Mögliche Performanceprobleme bei vielen Beobachtern
  • Reihenfolge und Zeitpunkte der Benachrichtigungen sind nicht garantiert
  • Kann zu unerwarteten Nebenwirkungen führen, wenn Beobachter ihrerseits wieder Benachrichtigungen auslösen

Typische Anwendungsfälle

  • GUI-Systeme (z. B. Button → Listener)
  • Event-Systeme (z. B. Message Bus, Signals/Slots)
  • Datenbindung in MVVM-Architekturen
  • Echtzeitbenachrichtigung (z. B. Wetterstation, Börsenticker)

Varianten

  • Push-Modell: Das Subject sendet alle relevanten Daten mit der Benachrichtigung.
  • Pull-Modell: Der Observer ruft die benötigten Daten beim Subject selbst ab.

Vergleich mit ähnlichen Mustern

Muster Vergleich
Mediator-Entwurfsmuster Koordiniert mehrere Objekte zentral, anstatt direkte Benachrichtigungen zu senden.
Publisher-Subscriber-Muster Ähnlich, aber häufig über einen Message-Bus oder Event-Queue realisiert.
Reactor-Entwurfsmuster Ereignisgesteuert, aber auf System-Ebene (z. B. Socket-Ereignisse) statt auf Objektebene.

Siehe auch

Quellen