Menu
Coddy logo textTech

Beobachter-Muster

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 94 von 104.

Das Beobachter-Muster definiert eine Eins-zu-viele-Abhängigkeit zwischen Objekten: Wenn ein Objekt (das Subjekt) seinen Zustand ändert, werden alle seine abhängigen Objekte (die Beobachter) automatisch benachrichtigt. Dies ist ideal für Ereignissysteme, UI-Aktualisierungen oder jedes Szenario, in dem mehrere Objekte auf Änderungen reagieren müssen.

Das Muster umfasst zwei wesentliche Rollen: ein Subject, das eine Liste von Beobachtern verwaltet und sie benachrichtigt, sowie Observers, die eine Aktualisierungsschnittstelle implementieren:

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

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
    std::vector<Observer*> observers;
    int state = 0;
    
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 setState(int value) {
        state = value;
        notify();
    }
    
    void notify() {
        for (Observer* obs : observers) {
            obs->update(state);
        }
    }
};

class Display : public Observer {
    std::string name;
public:
    Display(const std::string& n) : name(n) {}
    void update(int value) override {
        std::cout << name << " received: " << value << "\n";
    }
};

int main() {
    Subject sensor;
    Display screen1("Screen1"), screen2("Screen2");
    
    sensor.attach(&screen1);
    sensor.attach(&screen2);
    sensor.setState(42);  // Beide Displays benachrichtigt
}

Wenn setState() aufgerufen wird, durchläuft das Subjekt alle registrierten Beobachter und ruft ihre update()-Methode auf. Beobachter können jederzeit angefügt oder entfernt werden, wodurch das System flexibel und lose gekoppelt bleibt.

Verwende Observer, wenn Änderungen an einem Objekt eine Aktualisierung anderer Objekte erfordern und du diese Objekte nicht eng miteinander koppeln möchtest.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Weather Station-Überwachungssystem mithilfe des Observer-Musters. Du erstellst eine Wetterstation, die Temperaturdaten erfasst und mehrere Anzeigeeinheiten automatisch benachrichtigt, sobald sich die Temperatur ändert: eine klassische Anwendung dieses Musters aus der realen Welt.

Du organisierst deinen Code auf drei Dateien verteilt:

  • Observer.h: Definiere die Observer-Schnittstelle und einen konkreten Anzeige-Observer.

    Erstelle eine abstrakte Observer-Klasse mit einer rein virtuellen Methode update(double temperature), die Observer implementieren, um Benachrichtigungen zu empfangen, sowie einem virtuellen Destruktor.

    Erstelle anschließend eine TemperatureDisplay-Klasse, die von Observer erbt. Jede Anzeige hat einen Namen (String), der über ihren Konstruktor festgelegt wird. Wenn update() aufgerufen wird, soll sie Folgendes ausgeben:

    [DisplayName]: Temperature is [temperature] degrees
  • WeatherStation.h: Erstelle das Subjekt, das die Temperatur verwaltet und Observer benachrichtigt.

    Deine WeatherStation-Klasse sollte:

    • Eine Liste von Observer-Zeigern und die aktuelle Temperatur speichern (mit 0.0 initialisieren)
    • Eine attach(Observer* obs)-Methode zum Registrieren von Observern besitzen
    • Eine detach(Observer* obs)-Methode zum Entfernen von Observern besitzen
    • Eine setTemperature(double temp)-Methode besitzen, die die Temperatur aktualisiert und alle angefügten Observer benachrichtigt
    • Eine private notify()-Methode besitzen, die bei jedem Observer update() mit der aktuellen Temperatur aufruft
  • main.cpp: Veranschauliche das Observer-Muster in Aktion.

    Lies drei Eingaben ein:

    1. Name für die erste Anzeige (String)
    2. Name für die zweite Anzeige (String)
    3. Einen Temperaturwert (Double)

    Erstelle eine WeatherStation und zwei TemperatureDisplay-Objekte mit den angegebenen Namen. Füge beide Anzeigen zur Station hinzu und setze anschließend die Temperatur auf den Eingabewert. Beide Anzeigen sollten die Aktualisierung automatisch empfangen und ihre Nachrichten ausgeben.

    Entferne danach die erste Anzeige und setze eine neue Temperatur, die 5 Grad höher als der Eingabewert ist. Nur die zweite Anzeige sollte diese Aktualisierung empfangen.

Beispielsweise mit den Eingaben Kitchen, Bedroom und 22.5:

Kitchen: Temperature is 22.5 degrees
Bedroom: Temperature is 22.5 degrees
Bedroom: Temperature is 27.5 degrees

Mit den Eingaben Office, Lobby und 18.0:

Office: Temperature is 18 degrees
Lobby: Temperature is 18 degrees
Lobby: Temperature is 23 degrees

Beachte, wie das Observer-Muster ein lose gekoppeltes System schafft: Die Wetterstation muss nichts über die spezifischen Anzeigen wissen, sondern benachrichtigt einfach jeden, der zuhört. Wenn du einen Observer entfernst, empfängt er automatisch keine Aktualisierungen mehr.

Probier es selbst

#include <iostream>
#include <string>
#include "WeatherStation.h"

using namespace std;

int main() {
    // Eingaben lesen
    string display1Name, display2Name;
    double temperature;
    
    cin >> display1Name;
    cin >> display2Name;
    cin >> temperature;
    
    // TODO: Erstelle ein WeatherStation-Objekt
    
    // TODO: Erstelle zwei TemperatureDisplay-Objekte mit den Eingabenamen
    
    // TODO: Hänge beide Displays an die Wetterstation an
    
    // TODO: Setze die Temperatur auf den Eingabewert
    // (Beide Displays sollten ihre Nachrichten ausgeben)
    
    // TODO: Hänge das erste Display ab
    
    // TODO: Setze die Temperatur auf 5 Grad höher als die Eingabe
    // (Nur das zweite Display sollte ausgeben)
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C++-Compiler