Menu
Coddy logo textTech

Zustandsmuster

Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy — Lektion 60 von 70.

Das State-Pattern ist ein Verhaltensmuster, das es einem Objekt ermöglicht, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert. Anstatt komplexe bedingte Anweisungen zu verwenden, um verschiedene Zustände zu handhaben, kapseln Sie jeden Zustand in seiner eigenen Klasse und delegieren das Verhalten an das aktuelle Zustandsobjekt.

Das Muster besteht aus drei Komponenten: einem State-Interface, das zustandsspezifisches Verhalten definiert, konkreten State-Klassen, die dieses Verhalten implementieren, und einer Kontext-Klasse, die eine Referenz auf den aktuellen Zustand hält:

public interface IDocumentState
{
    void Publish(Document doc);
}

public class DraftState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Moving to moderation");
        doc.SetState(new ModerationState());
    }
}

public class ModerationState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Publishing document");
        doc.SetState(new PublishedState());
    }
}

public class PublishedState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Already published");
    }
}

Der Kontext hält den aktuellen Zustand und delegiert Aktionen an diesen. Zustandsobjekte können Übergänge auslösen, indem sie SetState() auf dem Kontext aufrufen:

public class Document
{
    private IDocumentState _state = new DraftState();
    
    public void SetState(IDocumentState state) => _state = state;
    
    public void Publish() => _state.Publish(this);
}

var doc = new Document();
doc.Publish();  // Wechsel zur Moderation
doc.Publish();  // Dokument wird veröffentlicht
doc.Publish();  // Bereits veröffentlicht

Das State-Pattern eliminiert ausufernde if-else- oder switch-Anweisungen, die den aktuellen Zustand prüfen. Jede Zustands-Klasse behandelt nur ihr eigenes Verhalten, wodurch der Code einfacher zu warten und um neue Zustände zu erweitern ist.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Ampelsystem mit dem State-Pattern erstellen. Ampeln durchlaufen verschiedene Zustände (Rot, Gelb, Grün), und jeder Zustand bestimmt, was passiert, wenn die Ampel umschaltet. Anstatt komplexe Bedingungen zu verwenden, kapseln Sie jeden Ampelzustand in einer eigenen Klasse.

Sie organisieren Ihren Code in drei Dateien:

  • TrafficLightState.cs: Definieren Sie ein ITrafficLightState-Interface im Namespace Traffic mit einer Methode Change(TrafficLight light). Erstellen Sie dann drei konkrete Zustandsklassen:
    • RedState - wenn Change aufgerufen wird, gibt sie Red - Stop! Changing to Green... aus und versetzt die Ampel in den GreenState
    • GreenState - gibt Green - Go! Changing to Yellow... aus und wechselt in den YellowState
    • YellowState - gibt Yellow - Caution! Changing to Red... aus und wechselt in den RedState
  • TrafficLight.cs: Erstellen Sie eine Klasse TrafficLight im selben Namespace. Dies ist Ihre Kontextklasse, die den aktuellen Zustand verwaltet. Sie sollte standardmäßig im RedState starten und Folgendes enthalten:
    • Eine Methode SetState(ITrafficLightState state), die von Zustandsobjekten verwendet wird, um Übergänge auszulösen
    • Eine Methode Change(), die den Aufruf an die Change-Methode des aktuellen Zustands delegiert
  • Program.cs: Führen Sie alles zusammen, indem Sie eine TrafficLight erstellen und die Zustandsänderungen basierend auf der Eingabe durchlaufen.

Sie erhalten eine Eingabe:

  • Die Anzahl der Male, die die Ampel umgeschaltet werden soll (eine Ganzzahl)

Erstellen Sie eine TrafficLight (die bei Rot beginnt) und rufen Sie Change() so oft wie angegeben auf.

Wenn die Eingabe beispielsweise 3 ist, sollte die Ausgabe wie folgt aussehen:

Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...

Wenn die Eingabe 5 ist, durchläuft die Ampel den Zyklus erneut:

Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...

Beachten Sie, dass die Klasse TrafficLight keine Logik darüber enthält, was jede Farbe bedeutet oder was als Nächstes kommt – all dieses Wissen befindet sich in den einzelnen Zustandsklassen. Jeder Zustand ist für sein eigenes Verhalten und für das Auslösen des Übergangs in den nächsten Zustand verantwortlich!

Spickzettel

Das State-Pattern (Zustandsmuster) ist ein Verhaltensmuster, das es einem Objekt ermöglicht, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert. Anstatt komplexe bedingte Anweisungen zu verwenden, kapseln Sie jeden Zustand in einer eigenen Klasse und delegieren das Verhalten an das aktuelle Zustandsobjekt.

Das Muster besteht aus drei Komponenten:

  • State-Interface: Definiert zustandsspezifisches Verhalten
  • Konkrete Zustands-Klassen: Implementieren das Verhalten für jeden Zustand
  • Kontext-Klasse: Hält eine Referenz auf den aktuellen Zustand

Beispielhafte Implementierung:

// State-Interface
public interface IDocumentState
{
    void Publish(Document doc);
}

// Konkrete Zustands-Klassen
public class DraftState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Moving to moderation");
        doc.SetState(new ModerationState());
    }
}

public class ModerationState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Publishing document");
        doc.SetState(new PublishedState());
    }
}

public class PublishedState : IDocumentState
{
    public void Publish(Document doc)
    {
        Console.WriteLine("Already published");
    }
}

// Kontext-Klasse
public class Document
{
    private IDocumentState _state = new DraftState();
    
    public void SetState(IDocumentState state) => _state = state;
    
    public void Publish() => _state.Publish(this);
}

// Verwendung
var doc = new Document();
doc.Publish();  // Moving to moderation
doc.Publish();  // Publishing document
doc.Publish();  // Already published

Der Kontext hält den aktuellen Zustand und delegiert Aktionen an diesen. Zustandsobjekte können Übergänge auslösen, indem sie SetState() auf dem Kontext aufrufen. Dies eliminiert ausufernde if-else- oder switch-Anweisungen und macht den Code einfacher zu warten und um neue Zustände zu erweitern.

Probier es selbst

using System;
using Traffic;

class Program
{
    public static void Main(String[] args)
    {
        // Lies die Anzahl der Male, die die Ampel umgeschaltet werden soll
        int n = Convert.ToInt32(Console.ReadLine());

        // TODO: Erstelle eine TrafficLight-Instanz (startet standardmäßig im RedState)

        // TODO: Rufe die Methode Change() n-mal mithilfe einer Schleife auf
    }
}
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