Zustandsmuster - State pattern

Das Zustandsmuster ist ein verhaltensbezogenes Software-Entwurfsmuster, das es einem Objekt ermöglicht, sein Verhalten zu ändern, wenn sich sein interner Zustand ändert. Dieses Muster kommt dem Konzept der endlichen Automaten sehr nahe . Das Zustandsmuster kann als Strategiemuster interpretiert werden , das in der Lage ist, eine Strategie durch Aufrufe von Methoden zu wechseln, die in der Schnittstelle des Musters definiert sind.

Das Zustandsmuster wird in der Computerprogrammierung verwendet , um variierendes Verhalten für dasselbe Objekt basierend auf seinem internen Zustand zu kapseln . Dies kann ein sauberer Weg für ein Objekt sein, sein Verhalten zur Laufzeit zu ändern, ohne auf bedingte Anweisungen zurückgreifen zu müssen und somit die Wartbarkeit zu verbessern.

Überblick

Ein Beispiel für ein UML-Klassen- und Sequenzdiagramm für das State-Entwurfsmuster.

Das State Design Pattern ist eines von dreiundzwanzig von der Gang of Four dokumentierten Designmustern , die beschreiben, wie wiederkehrende Designprobleme gelöst werden können. Solche Probleme umfassen den Entwurf flexibler und wiederverwendbarer objektorientierter Software, wie beispielsweise Objekte, die leicht zu implementieren, zu ändern, zu testen und wiederzuverwenden sind.

Das Zustandsmuster soll zwei Hauptprobleme lösen:

  • Ein Objekt sollte sein Verhalten ändern, wenn sich sein interner Zustand ändert.
  • Zustandsspezifisches Verhalten sollte unabhängig definiert werden. Das heißt, das Hinzufügen neuer Zustände sollte sich nicht auf das Verhalten bestehender Zustände auswirken.

Die Implementierung von zustandsspezifischem Verhalten direkt innerhalb einer Klasse ist unflexibel, da es die Klasse auf ein bestimmtes Verhalten festlegt und es unmöglich macht, später unabhängig von der Klasse einen neuen Zustand hinzuzufügen oder das Verhalten eines bestehenden Zustands zu ändern, ohne die Klasse zu ändern. Dabei beschreibt das Muster zwei Lösungen:

  • Definieren Sie separate (Zustands-)Objekte, die zustandsspezifisches Verhalten für jeden Zustand kapseln. Das heißt, definieren Sie eine Schnittstelle (einen Zustand) zum Durchführen von zustandsspezifischem Verhalten und definieren Sie Klassen, die die Schnittstelle für jeden Zustand implementieren.
  • Eine Klasse delegiert zustandsspezifisches Verhalten an ihr aktuelles Zustandsobjekt, anstatt zustandsspezifisches Verhalten direkt zu implementieren.

Dies macht eine Klasse unabhängig davon, wie zustandsspezifisches Verhalten implementiert ist. Neue Zustände können hinzugefügt werden, indem neue Zustandsklassen definiert werden. Eine Klasse kann ihr Verhalten zur Laufzeit ändern, indem sie ihr aktuelles Zustandsobjekt ändert.


Struktur

Staat in UML

Im zugehörigen Klassendiagramm der Unified Modeling Language (UML) implementiert die Klasse das zustandsspezifische Verhalten nicht direkt. Bezieht sich stattdessen auf die Schnittstelle zum Durchführen von zustandsspezifischem Verhalten ( ), die unabhängig davon macht, wie zustandsspezifisches Verhalten implementiert wird. Die Klassen und implementieren die Schnittstelle, dh implementieren (kapseln) das zustandsspezifische Verhalten für jeden Zustand. Das UML- Sequenzdiagramm zeigt die Laufzeitinteraktionen: ContextContextStatestate.operation()ContextState1State2State

Das ContextObjekt delegiert zustandsspezifisches Verhalten an verschiedene StateObjekte. Erstens ContextAnrufe operation(this)auf seinem aktuellen (anfängliches) Zustandsobjekt ( State1), die den Betrieb und die Anrufe durchführt setState(State2)auf Contextdem Kontext des aktuellen Zustand zu ändern State2. Ruft beim nächsten Mal Contextwieder operation(this)sein aktuelles Zustandsobjekt ( State2) auf, das die Operation ausführt und den aktuellen Zustand des Kontexts in ändert State1.

Beispiel

Java

Die Zustandsschnittstelle und zwei Implementierungen. Die Methode des Zustands hat eine Referenz auf das Kontextobjekt und kann seinen Zustand ändern.

interface State {
    void writeName(StateContext context, String name);
}

class LowerCaseState implements State {
    @Override
    public void writeName(StateContext context, String name) {
        System.out.println(name.toLowerCase());
        context.setState(new MultipleUpperCaseState());
    }
}

class MultipleUpperCaseState implements State {
    /* Counter local to this state */
    private int count = 0;

    @Override
    public void writeName(StateContext context, String name) {
        System.out.println(name.toUpperCase());
        /* Change state after StateMultipleUpperCase's writeName() gets invoked twice */
        if (++count > 1) {
            context.setState(new LowerCaseState());
        }
    }
}

Die Kontextklasse hat eine Zustandsvariable, die sie in einem Anfangszustand instanziiert, in diesem Fall LowerCaseState. Es verwendet in seiner Methode die entsprechenden Methoden des Zustandsobjekts.

class StateContext {
    private State state;
    
    public StateContext() {
        state = new LowerCaseState();
    }

    /**
     * Set the current state.
     * Normally only called by classes implementing the State interface.
     * @param newState the new state of this context
     */
    void setState(State newState) {
        state = newState;
    }

    public void writeName(String name) {
        state.writeName(this, name);
    }
}

Die folgende Demonstration zeigt die Verwendung:

public class StateDemo {
    public static void main(String[] args) {
        StateContext context = new StateContext();

        context.writeName("Monday");
        context.writeName("Tuesday");
        context.writeName("Wednesday");
        context.writeName("Thursday");
        context.writeName("Friday");
        context.writeName("Saturday");
        context.writeName("Sunday");
    }
}

Mit dem obigen Code lautet die Ausgabe von main()from StateDemo:

 monday
 TUESDAY
 WEDNESDAY
 thursday
 FRIDAY
 SATURDAY
 sunday

Verweise