State Pattern-CLI: Refactoring - Zustands-Singletons mit Enums
https://bildung.social/@oerinformatik/110504024656041988
https://oer-informatik.de/state-pattern-cli2
tl/dr; (ca. 5 min Lesezeit): Am Beispiel eines Command-Line-Interfaces wird das State-Pattern beispielhaft in Java implementiert. In diesem Teil geht es um das Instanzenmanagement der einzelnen Zustandsklassen mit Hilfe von Singletons/ENUMS. (Zuletzt geändert am 11.06.2023)
- Aufbau des State-Patterns allgemein und grundlegende Struktur
- Realisierung der Zustände als Singletons (per Java-ENUMS)(dieser Artikel)
- Realisierung der Transitionen und deren Trigger
- Realisierung von Effekten und Guards von Transitionen
Das bisherige Grundgerüst
Es soll eine rudimentäre Kommandozeilen-Benutzeroberfläche für ein Programm mit Hilfe des State-Pattern erstellt werden. Im ersten Teil haben wir uns das State-Pattern selbst angeschaut und die Grundstruktur für Zustandswechsel festgelegt. Bei einem Zustandswechsel haben wir im letzten Codebeispiel einfach eine neue Instanz erstellt (myUI.setState(new ListUI());
). Das muss natürlich optimiert werden. Wir fügen jetzt ein Instanzenmanagement für das Projekt an. Um das große Ganze nich aus dem Blick zu verlieren werfen wir zunächst wieder einen Blick auf die Navigation, die wir modelliert hatten:

Die einzelnen Zustände hatten wir bereits über das State-Pattern modelliert, bislang jedoch nur die beiden Zustandsklassen ListUI
und ‘AnmeldenUI’ implementiert. Das Verhalten ist bisher noch komplett in der vorgeschalteten abstrakten Klasse AbstractUIState
realisiert. Unser Grundgerüst als Klassendiagramm sieht folgendermaßen aus:

Zur Orientierung nochmal im Schnelldurchlauf die Aufgaben der bisherigen Klassen:
Die Kontext-Klasse
UIContext
ist Basis des Objekts, dessen Zustand sich ändern soll.Die Zustandsklassen (beispielhaft
AnmeldenUI
undListUI
) bestimmen später das Verhalten vonUIContext
in bestimmten Zuständen.Das Interface
UIStateInterface
setzt die lose Kopplung der Zustandsklassen mit dem Kontext um.Die abstrakte Klasse
AbstractUIState
stellt die gemeinsame Implementierungen aller Zustandsklassen bereit.
Denkbar wäre auch, das Interface komplett durch die abstrakte Klasse zu ersetzen. Wir haben diese beiden Aufgaben hier aber getrennt.
Zustände als Singletons / Variante: in ENUM-Klasse kapseln (Klasse UIStateEnum
)
In diesem Schritt wollen wir dem Projekt keinerlei neue Funktionalität zuweisen, sondern die Struktur verbessern, also ein reines Refactoring durchführen: Von jeder Zustandsklasse wird lediglich ein einziges Objekt benötigt, es würde sich also anbieten, diese Klassen als Singleton zu implementieren - also dafür zu sorgen, dass immer auf die gleiche Instanz der Klasse zugegriffen wird.
Eine praktische Variante stellt die Nutzung eines Aufzählungsobjekts (ENUM
) dar. Eine Aufzählung ist in Java ein Singleton und kann die Instanzen der Zustandsklassen kapseln. Die Zustandsklassen selbst müssen dann nicht als Singleton realisiert sein.
Wir erstellen eine ENUM
-Klasse, von dieser Klasse Instanziieren wir für jeden Zustand eine Instanz: ANMELDEN_UI
, LIST_UI
usw.

ANMELDEN_UI
ist also eine Instanz von UIStateEnum. Da wir in dieser Instanz ein Objekt speichern wollen, das UIStateInterface
implementiert, müssen wir dieses übergeben. Dazu nutzen wir direkt den Konstruktor. Wir notieren also in der ENUM-Liste die Konstruktor-Aufrufe mit Parametern: (z.B. ANMELDEN_UI(new AnmeldenUI())
).
Jetzt müssen wir nur noch den Konstruktor implementieren UIStateEnum(...)
, der die entsprechenden UIStateInterface
Instanzen speichert (im Attribut uiObject
).
Die Basis-Implementierung von Klasse, Konstruktor und Attribut ist folgende:
public enum UIStateEnum {
ANMELDEN_UI(new AnmeldenUI()),
LIST_UI(new ListUI());
private final UIStateInterface uiObject;
UIStateEnum(UIStateInterface uiObject) {
this.uiObject = uiObject;
}
}
Zur Nutzung der UIStateEnums
benötigen wir noch Methoden, die uns die Zustandsklassenobjekte kapseln und entkapseln.
Das ist zum einen eine Methode, die bei vorliegendem Enum
-Objekt die gekapselte Zustandsklasse zurückgibt. Das ist schnell implementiert, da es sich nur um einen Getter für das Attribut handelt:
… sowie eine Methode, die für ein vorliegendes Zustandsklassenobjekt das zugehörige Enum
-Objekt findet. Dazu müssen wir in die Trickkiste greifen, und für jedes Objekt mithilfe des instanceof
-Operators das zugehörige Enum
suchen:
public static UIStateEnum getUIStateEnum(Object usedObject) {
if (usedObject instanceof AnmeldenUI) {return ANMELDEN_UI;}
if (usedObject instanceof ListUI) {return LIST_UI;}
return null;
}
An der Gesamtstruktur unseres Projekt ändert sich damit einiges: Der Kontext aggregiert nicht mehr die Zustandsobjekte, sondern er aggregiert das Enum
:
Im Kontext ändert sich entsprechend das Attribut state
und der zugehörige Setter zu:
private UIStateEnum uiStateEnum;
public void setUiStateEnum(UIStateEnum newUiStateEnum) {
this.uiStateEnum = newUiStateEnum;
}
In der Main-Methode wird entsprechend der neue Setter aufgerufen…
public static void main(String[] args) {
...
myUI.setUiStateEnum(UIStateEnum.ANMELDEN_UI);
...
myUI.setUiStateEnum(UIStateEnum.LIST_UI);
...}
… und die drei Methoden entry()
, doing()
und exit()
des Kontexts greifen gekapselt über das Enum
auf die Zustandsobjekte zu. Dazu nutzen sie den Getter, den wir in der Enum
-Klasse implementiert hatten. Beispielhaft für entry()
:
Nächste Schritte
Bis hierhin haben wir keinerlei neue Funktionalität hinzugefügt, ein Test des Programms sollte also wieder exakt das gleiche Ergebnis hervorbringen wie vor der Enum
-Anpassung.
Hinweis zur Nachnutzung als Open Educational Resource (OER)
Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “State Pattern-CLI: Refactoring - Zustands-Singletons mit Enums” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/state-pattern-cli2 veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/design-pattern/state-pattern. Stand: 11.06.2023.
[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]