Menu
Coddy logo textTech

State-Muster

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 74 von 87.

Das State Pattern ist ein Verhaltensmuster, das es einem Objekt ermöglicht, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert. Das Objekt scheint seine Klasse zu ändern, aber in Wirklichkeit delegiert es das Verhalten an verschiedene Zustandsobjekte. Denken Sie an einen Verkaufsautomaten: Seine Reaktion auf das Drücken einer Taste hängt davon ab, ob er im Leerlauf ist, Geld eingeworfen wurde oder ein Produkt ausgibt.

Anstatt komplexe bedingte Anweisungen zu verwenden, um verschiedene Zustände zu handhaben, kapseln Sie jeden Zustand in seiner eigenen Klasse. Das Muster umfasst einen Context, der eine Referenz auf den aktuellen Zustand hält, und State-Klassen, die das Verhalten für jeden Zustand definieren:

interface State {
    void handle(Context context);
}

class Context {
    private State state;
    
    public void setState(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }
}

Jeder konkrete Zustand implementiert das Verhalten und kann Übergänge in andere Zustände auslösen:

class IdleState implements State {
    public void handle(Context context) {
        System.out.println("Idle: Insert coin to start");
        context.setState(new ActiveState());
    }
}

class ActiveState implements State {
    public void handle(Context context) {
        System.out.println("Active: Processing...");
        context.setState(new IdleState());
    }
}

Der Kontext delegiert Anfragen an seinen aktuellen Zustand, und das Verhalten ändert sich automatisch, wenn sich der Zustand ändert:

Context context = new Context();
context.setState(new IdleState());

context.request();  // Leerlauf: Münze einwerfen, um zu starten
context.request();  // Aktiv: Verarbeitung...

Das State Pattern (Zustandsmuster) ist ideal, wenn das Verhalten eines Objekts stark von seinem Zustand abhängt und sich zur Laufzeit ändern muss. Es eliminiert große bedingte Blöcke und macht das Hinzufügen neuer Zustände unkompliziert – erstellen Sie einfach eine neue Klasse, die das State-Interface implementiert.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Dokumenten-Workflow-System mit dem State Pattern erstellen! Sie werden ein System entwickeln, das modelliert, wie ein Dokument verschiedene Phasen durchläuft – Draft, Review und Published – wobei jeder Zustand bestimmt, welche Aktionen verfügbar sind und wie sich das Dokument verhält, wenn Sie versuchen, es zu bearbeiten oder zu genehmigen.

Sie werden Ihren Code in vier Dateien organisieren:

  • DocumentState.java: Definieren Sie das DocumentState-Interface, das alle Zustände implementieren werden. Es sollte zwei Methoden deklarieren: edit(Document doc) für den Versuch, das Dokument zu bearbeiten, und approve(Document doc) für den Versuch, das Dokument zu genehmigen oder in die nächste Phase zu befördern.
  • States.java: Erstellen Sie drei konkrete Zustandsklassen, die DocumentState implementieren:

    DraftState - Wenn edit aufgerufen wird, geben Sie Editing draft... aus. Wenn approve aufgerufen wird, geben Sie Draft approved. Moving to review. aus und versetzen Sie das Dokument in den ReviewState.

    ReviewState - Wenn edit aufgerufen wird, geben Sie Cannot edit during review. aus (keine Zustandsänderung). Wenn approve aufgerufen wird, geben Sie Review complete. Publishing document. aus und wechseln Sie in den PublishedState.

    PublishedState - Wenn edit aufgerufen wird, geben Sie Cannot edit published document. aus. Wenn approve aufgerufen wird, geben Sie Document already published. aus. Keine der Aktionen ändert den Zustand.

  • Document.java: Erstellen Sie die Kontextklasse, die den aktuellen Zustand verwaltet. Ihr Document sollte Folgendes haben:

    Ein privates Feld, das den aktuellen DocumentState hält und im Konstruktor mit DraftState initialisiert wird.

    Eine setState(DocumentState state)-Methode, die den aktuellen Zustand ändert.

    Eine edit()-Methode, die an die edit-Methode des aktuellen Zustands delegiert.

    Eine approve()-Methode, die an die approve-Methode des aktuellen Zustands delegiert.

    Eine getStatus()-Methode, die den einfachen Klassennamen des aktuellen Zustands zurückgibt (verwenden Sie getClass().getSimpleName()).

  • Main.java: Demonstrieren Sie Ihr Zustandssystem! Sie erhalten eine Eingabe: eine Sequenz von Aktionen als kommagetrennte Zeichenfolge, wobei jede Aktion entweder edit oder approve ist (zum Beispiel: edit,approve,edit,approve).

    Erstellen Sie ein Document und geben Sie seinen Anfangsstatus im Format Status: [state] aus. Verarbeiten Sie dann jede Aktion nacheinander, indem Sie die entsprechende Methode auf dem Dokument aufrufen. Geben Sie nach jeder Aktion den aktuellen Status aus.

Sie erhalten eine Eingabe: eine kommagetrennte Zeichenfolge von Aktionen.

Zum Beispiel würde bei der Eingabe edit,approve,approve Ihre Ausgabe so aussehen:

Status: DraftState
Editing draft...
Status: DraftState
Draft approved. Moving to review.
Status: ReviewState
Review complete. Publishing document.
Status: PublishedState

Beachten Sie, wie derselbe approve()-Aufruf je nach aktuellem Zustand des Dokuments unterschiedliche Ergebnisse liefert – das ist der Kern des State Patterns! Das Dokument verwendet keine Bedingungen, um seinen Zustand zu prüfen; stattdessen delegiert es das Verhalten an das aktuelle Zustandsobjekt, das die Aktion angemessen verarbeitet und bei Bedarf Übergänge auslöst.

Spickzettel

Das State Pattern (Zustandsmuster) ist ein Verhaltensmuster, das es einem Objekt ermöglicht, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert, indem es das Verhalten an verschiedene Zustandsobjekte delegiert, anstatt komplexe bedingte Anweisungen zu verwenden.

Das Muster besteht aus einem Context, der eine Referenz auf den aktuellen Zustand hält, und State-Klassen, die das Verhalten für jeden Zustand definieren:

interface State {
    void handle(Context context);
}

class Context {
    private State state;
    
    public void setState(State state) {
        this.state = state;
    }
    
    public void request() {
        state.handle(this);
    }
}

Jeder konkrete Zustand implementiert das Verhalten und kann Übergänge in andere Zustände auslösen:

class IdleState implements State {
    public void handle(Context context) {
        System.out.println("Idle: Insert coin to start");
        context.setState(new ActiveState());
    }
}

class ActiveState implements State {
    public void handle(Context context) {
        System.out.println("Active: Processing...");
        context.setState(new IdleState());
    }
}

Der Kontext delegiert Anfragen an seinen aktuellen Zustand, und das Verhalten ändert sich automatisch, wenn sich der Zustand ändert:

Context context = new Context();
context.setState(new IdleState());

context.request();  // Idle: Insert coin to start
context.request();  // Active: Processing...

Das State Pattern ist ideal, wenn das Verhalten eines Objekts stark von seinem Zustand abhängt und sich zur Laufzeit ändern muss. Es eliminiert große bedingte Blöcke und macht das Hinzufügen neuer Zustände unkompliziert.

Probier es selbst

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Erstelle ein neues Dokument
        
        // TODO: Gib den ursprünglichen Status im Format "Status: [state]" aus
        
        // TODO: Teile die Eingabe durch Komma, um einzelne Aktionen zu erhalten
        
        // TODO: Durchlaufe jede Aktion in einer Schleife
        // - Wenn die Aktion "edit" ist, rufe edit() auf dem Dokument auf
        // - Wenn die Aktion "approve" ist, rufe approve() auf dem Dokument auf
        // - Gib nach jeder Aktion den aktuellen Status aus
    }
}
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