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
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
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:
Context
Context
State
state.operation()
Context
State1
State2
State
Das Context
Objekt delegiert zustandsspezifisches Verhalten an verschiedene State
Objekte. Erstens Context
Anrufe operation(this)
auf seinem aktuellen (anfängliches) Zustandsobjekt ( State1
), die den Betrieb und die Anrufe durchführt setState(State2)
auf Context
dem Kontext des aktuellen Zustand zu ändern State2
. Ruft beim nächsten Mal Context
wieder 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