Menu
Coddy logo textTech

State-Muster

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

Das State-Pattern (Zustandsmuster) ermöglicht es einem Objekt, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert, sodass es so aussieht, als ob das Objekt seine Klasse gewechselt hätte. Anstatt komplexe bedingte Anweisungen zu verwenden, um verschiedene Zustände zu handhaben, kapseln Sie jeden Zustand als eine separate Klasse.

Das Muster besteht aus einem Context, der eine Referenz auf den aktuellen Zustand hält, einem State interface, das zustandsspezifisches Verhalten definiert, und Concrete States, die das Verhalten für jeden Zustand implementieren:

#include <iostream>
#include <memory>

class Document;  // Vorwärtsdeklaration

// Zustands-Interface
class DocumentState {
public:
    virtual void publish(Document& doc) = 0;
    virtual std::string getName() const = 0;
    virtual ~DocumentState() = default;
};

// Kontext
class Document {
    std::unique_ptr<DocumentState> state;
public:
    Document();
    void setState(std::unique_ptr<DocumentState> newState) {
        state = std::move(newState);
    }
    void publish() { state->publish(*this); }
    std::string getStateName() const { return state->getName(); }
};

// Konkrete Zustände
class Draft : public DocumentState {
public:
    void publish(Document& doc) override;
    std::string getName() const override { return "Draft"; }
};

class Review : public DocumentState {
public:
    void publish(Document& doc) override;
    std::string getName() const override { return "Review"; }
};

class Published : public DocumentState {
public:
    void publish(Document& doc) override {
        std::cout << "Already published\n";
    }
    std::string getName() const override { return "Published"; }
};

void Draft::publish(Document& doc) {
    std::cout << "Moving to review\n";
    doc.setState(std::make_unique<Review>());
}

void Review::publish(Document& doc) {
    std::cout << "Publishing document\n";
    doc.setState(std::make_unique<Published>());
}

Document::Document() : state(std::make_unique<Draft>()) {}

Jeder Zustand verarbeitet die publish()-Aktion unterschiedlich und ist für den Übergang in den nächsten Zustand verantwortlich. Das Document muss die Übergangslogik nicht kennen – es delegiert einfach an den aktuellen Zustand. Dies eliminiert große Switch-Anweisungen und macht das Hinzufügen neuer Zustände unkompliziert.

Verwenden Sie State, wenn das Verhalten eines Objekts stark von seinem Zustand abhängt und Sie viele bedingte Anweisungen haben, die je nach Zustand des Objekts umschalten.

challenge icon

Aufgabe

Einfach

Lassen Sie uns eine Ampelsteuerung mit dem State-Pattern (Zustandsmuster) erstellen. Sie werden ein System entwickeln, bei dem eine Ampel verschiedene Zustände (Red, Yellow, Green) durchläuft, wobei jeder Zustand bestimmt, was passiert, wenn die Ampel umschaltet und welche Nachricht angezeigt wird. Dies ist ein klassisches Beispiel für das State-Pattern – das Verhalten der Ampel hängt vollständig von ihrem aktuellen Zustand ab.

Sie werden Ihren Code auf drei Dateien verteilen:

  • TrafficLightState.h: Definieren Sie das State-Interface und alle konkreten Zustandsklassen.

    Erstellen Sie eine abstrakte Klasse TrafficLightState mit:

    • Einer rein virtuellen Methode change(TrafficLight& light), die den Übergang zum nächsten Zustand handhabt
    • Einer rein virtuellen Methode getColor(), die die aktuelle Farbe als String zurückgibt
    • Einer rein virtuellen Methode getAction(), die zurückgibt, was Fahrer tun sollten (z. B. "Stop", "Caution", "Go")
    • Einem virtuellen Destruktor

    Implementieren Sie drei konkrete Zustände:

    • RedState — Farbe ist "Red", Aktion ist "Stop", wechselt zu Green
    • YellowState — Farbe ist "Yellow", Aktion ist "Caution", wechselt zu Red
    • GreenState — Farbe ist "Green", Aktion ist "Go", wechselt zu Yellow

    Sie benötigen eine Vorwärtsdeklaration für TrafficLight, da die Zustände darauf verweisen.

  • TrafficLight.h: Erstellen Sie die Kontext-Klasse, die den aktuellen Zustand verwaltet.

    Ihre Klasse TrafficLight sollte einen std::unique_ptr<TrafficLightState> halten und standardmäßig im Zustand Red starten. Implementieren Sie:

    • setState(std::unique_ptr<TrafficLightState> newState) — ändert den aktuellen Zustand
    • change() — delegiert an die change-Methode des aktuellen Zustands
    • display() — gibt den Status der Ampel im Format [Color]: [Action] aus
  • main.cpp: Demonstrieren Sie, wie die Ampel die Zustände durchläuft.

    Lesen Sie eine Eingabe ein: die Anzahl der durchzuführenden Zustandsänderungen (Ganzzahl).

    Erstellen Sie ein TrafficLight-Objekt und zeigen Sie dessen Anfangszustand an. Führen Sie dann die angegebene Anzahl an Änderungen durch und zeigen Sie den Zustand nach jeder Änderung an.

Zum Beispiel bei der Eingabe 3:

Red: Stop
Green: Go
Yellow: Caution
Red: Stop

Bei der Eingabe 6:

Red: Stop
Green: Go
Yellow: Caution
Red: Stop
Green: Go
Yellow: Caution
Red: Stop

Beachten Sie, wie die Ampel ihre Zustände in einem vorhersehbaren Muster durchläuft: Red → Green → Yellow → Red. Jeder Zustand weiß, welcher Zustand als Nächstes kommt, und verwaltet seinen eigenen Übergang. Die Klasse TrafficLight benötigt keine bedingte Logik, um zu bestimmen, was passiert – sie delegiert einfach an den Zustand, in dem sie sich gerade befindet.

Probier es selbst

#include <iostream>
#include "TrafficLight.h"

using namespace std;

int main() {
    // Die Anzahl der Zustandsänderungen einlesen
    int numChanges;
    cin >> numChanges;
    
    // TODO: Ein TrafficLight-Objekt erstellen
    
    // TODO: Den Anfangszustand anzeigen
    
    // TODO: Die angegebene Anzahl an Änderungen durchführen
    // Nach jeder Änderung den aktuellen Zustand anzeigen
    
    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