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.
Aufgabe
EinfachLassen 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 dasDocumentState-Interface, das alle Zustände implementieren werden. Es sollte zwei Methoden deklarieren:edit(Document doc)für den Versuch, das Dokument zu bearbeiten, undapprove(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, dieDocumentStateimplementieren:DraftState- Wenneditaufgerufen wird, geben SieEditing draft...aus. Wennapproveaufgerufen wird, geben SieDraft approved. Moving to review.aus und versetzen Sie das Dokument in denReviewState.ReviewState- Wenneditaufgerufen wird, geben SieCannot edit during review.aus (keine Zustandsänderung). Wennapproveaufgerufen wird, geben SieReview complete. Publishing document.aus und wechseln Sie in denPublishedState.PublishedState- Wenneditaufgerufen wird, geben SieCannot edit published document.aus. Wennapproveaufgerufen wird, geben SieDocument already published.aus. Keine der Aktionen ändert den Zustand.Document.java: Erstellen Sie die Kontextklasse, die den aktuellen Zustand verwaltet. IhrDocumentsollte Folgendes haben:Ein privates Feld, das den aktuellen
DocumentStatehält und im Konstruktor mitDraftStateinitialisiert wird.Eine
setState(DocumentState state)-Methode, die den aktuellen Zustand ändert.Eine
edit()-Methode, die an dieedit-Methode des aktuellen Zustands delegiert.Eine
approve()-Methode, die an dieapprove-Methode des aktuellen Zustands delegiert.Eine
getStatus()-Methode, die den einfachen Klassennamen des aktuellen Zustands zurückgibt (verwenden SiegetClass().getSimpleName()).Main.java: Demonstrieren Sie Ihr Zustandssystem! Sie erhalten eine Eingabe: eine Sequenz von Aktionen als kommagetrennte Zeichenfolge, wobei jede Aktion entwedereditoderapproveist (zum Beispiel:edit,approve,edit,approve).Erstellen Sie ein
Documentund geben Sie seinen Anfangsstatus im FormatStatus: [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: PublishedStateBeachten 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
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem9Generics
Einführung in GenericsGenerische KlassenGenerische MethodenEingeschränkte TypparameterWildcards (?, extends, super)Zusammenfassung – Generische Container12Entwurfsmuster Teil 2
Command-MusterAdapter-MusterDecorator-MusterTemplate-Method-MusterState-MusterComposite-MusterIterator-Muster