Menu
Coddy logo textTech

Zustandsmuster

Teil des Abschnitts Objektorientierte Programmierung der Dart-Journey von Coddy — Lektion 98 von 110.

Das State-Pattern 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 Bedingungen 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 einem Context, der eine Referenz auf den aktuellen Zustand hält, und State-Klassen, die das Verhalten für jeden möglichen Zustand definieren. Wenn sich der Zustand des Contexts ändert, ändert sich sein Verhalten automatisch:

abstract class DocumentState {
  void publish(Document doc);
  String getStatus();
}

class DraftState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Moving to review...');
    doc.setState(ReviewState());
  }

  @override
  String getStatus() => 'Draft';
}

class ReviewState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Document published!');
    doc.setState(PublishedState());
  }

  @override
  String getStatus() => 'Under Review';
}

class PublishedState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Already published.');
  }

  @override
  String getStatus() => 'Published';
}

class Document {
  DocumentState _state = DraftState();

  void setState(DocumentState state) => _state = state;
  void publish() => _state.publish(this);
  String getStatus() => _state.getStatus();
}

void main() {
  var doc = Document();
  print(doc.getStatus());  // Entwurf
  doc.publish();           // Wechsel zur Überprüfung...
  print(doc.getStatus());  // In Überprüfung
  doc.publish();           // Dokument veröffentlicht!
  print(doc.getStatus());  // Veröffentlicht
}

Jede Zustandsklasse behandelt die publish()-Aktion unterschiedlich und kann das Dokument in den nächsten Zustand überführen. Die Document-Klasse benötigt keine Bedingungen, um ihren aktuellen Zustand zu prüfen – sie delegiert einfach an das jeweils aktive Zustandsobjekt. Dieses Muster ist ideal für Objekte mit unterschiedlichen Verhaltensmodi, wie die Auftragsabwicklung, Mediaplayer oder Workflow-Systeme.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Ampelsystem mit dem State-Pattern bauen! Sie werden eine Ampel erstellen, die verschiedene Zustände durchläuft, wobei jeder Zustand die Farbe der Ampel bestimmt und festlegt, wie sie in den nächsten Zustand übergeht.

Sie werden Ihren Code in zwei Dateien organisieren:

  • traffic_light.dart: Diese Datei enthält Ihre Zustandsklassen und den Ampel-Kontext. Erstellen Sie eine abstrakte Klasse TrafficLightState mit zwei Methoden: String getColor(), die die aktuelle Ampelfarbe zurückgibt, und void next(TrafficLight light), die die Ampel in ihren nächsten Zustand überführt. Implementieren Sie drei konkrete Zustandsklassen:
    • RedState - gibt 'RED' als Farbe zurück und gibt 'Stop! Light is red.' aus, wenn next() aufgerufen wird, und wechselt dann zu GreenState
    • GreenState - gibt 'GREEN' als Farbe zurück und gibt 'Go! Light is green.' aus, wenn next() aufgerufen wird, und wechselt dann zu YellowState
    • YellowState - gibt 'YELLOW' als Farbe zurück und gibt 'Caution! Light is yellow.' aus, wenn next() aufgerufen wird, und wechselt dann zu RedState
    Erstellen Sie dann eine TrafficLight-Klasse (den Kontext), die im RedState startet. Sie sollte eine setState()-Methode haben, um den aktuellen Zustand zu ändern, eine getColor()-Methode, die an den aktuellen Zustand delegiert, und eine change()-Methode, die next() auf dem aktuellen Zustand aufruft.
  • main.dart: Importieren Sie Ihre Ampel-Datei und demonstrieren Sie das State-Pattern in Aktion. Erstellen Sie eine TrafficLight und geben Sie deren Anfangsfarbe aus. Rufen Sie dann dreimal change() auf und geben Sie nach jeder Änderung die Farbe aus. Dies zeigt, wie die Ampel alle Zustände durchläuft und zum Anfang zurückkehrt.

Beachten Sie, dass die TrafficLight-Klasse keine Bedingungen benötigt, um das Verhalten zu bestimmen – jeder Zustand kennt seine eigene Farbe und weiß, welcher Zustand als Nächstes kommt. Die Ampel delegiert einfach an den Zustand, der gerade aktiv ist!

Erwartete Ausgabe:

RED
Stop! Light is red.
GREEN
Go! Light is green.
YELLOW
Caution! Light is yellow.
RED

Spickzettel

Das State-Pattern ermöglicht es einem Objekt, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert. Anstatt komplexe Bedingungen zu verwenden, wird jeder Zustand in einer eigenen Klasse gekapselt.

Das Muster besteht aus:

  • Kontext: Hält eine Referenz auf den aktuellen Zustand
  • Zustandsklassen: Definieren das Verhalten für jeden möglichen Zustand

Grundstruktur:

abstract class DocumentState {
  void publish(Document doc);
  String getStatus();
}

class DraftState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Moving to review...');
    doc.setState(ReviewState());
  }

  @override
  String getStatus() => 'Draft';
}

class Document {
  DocumentState _state = DraftState();

  void setState(DocumentState state) => _state = state;
  void publish() => _state.publish(this);
  String getStatus() => _state.getStatus();
}

Der Kontext delegiert das Verhalten an das aktuelle Zustandsobjekt. Jede Zustandsklasse verarbeitet Aktionen unterschiedlich und kann in den nächsten Zustand übergehen. Dies macht Bedingungen zur Überprüfung des aktuellen Zustands überflüssig.

Ideal für Objekte mit unterschiedlichen Verhaltensmodi wie Auftragsabwicklung, Mediaplayer oder Workflow-Systeme.

Probier es selbst

import 'traffic_light.dart';

void main() {
  // TODO: Erstelle eine TrafficLight-Instanz
  
  // TODO: Gib die Ausgangsfarbe aus
  
  // TODO: Rufe change() auf und gib die Farbe aus (3 Mal, um alle Zustände zu durchlaufen)
  // Erster Wechsel: RED -> GREEN
  
  // Zweiter Wechsel: GREEN -> YELLOW
  
  // Dritter Wechsel: YELLOW -> RED
}
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