ModellierungzustandsorientierterSysteme inJava ...de.julian-fietkau.de/pdf/modellierung_zustands... · Nun gibt das Zustandsmuster allerdings nicht vor, welche Klasse oder Klassen
28
Modellierung zustandsorientierter Systeme in Java: Das Zustandsmuster, Varianten und Alternativen Julian Fietkau, Janina Nemec 28. August 2009 Seminararbeit im Seminar „Konzepte objektorientierter Programmiersprachen“ im Sommersemester 2009 Dozenten: Axel Schmolitzky, Christian Späh Seminar 64-162 im Sommersemester 2009 Arbeitsbereich Softwaretechnik (SWT) Department Informatik Universität Hamburg
6 Weitere Ansaumltze 1361 Objektbasiertes Zustandsgeflecht 1362 Enum mit Transitionstabelle 14
7 Zusammenfassung 14
Anhang 16Quelltext-Listings 16
1 Naive Umsetzung 162 Naive Umsetzung mit innerem Aufzaumlhlungstyp 173 Zustandsmuster mit dezentraler Transitionsverwaltung 184 Zustandsmuster mit zentraler Transitionsverwaltung 205 Externer Zustand als Aufzaumlhlungstyp 226 Objektbasiertes Zustandsgeflecht 247 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle 26
Literatur 28
Dieses Werk steht unter der Creative Commons Attribution 30 Lizenz Das bedeutet dass es mit wenigen Einschraumlnkungen kopiertverteilt und fuumlr jegliche Zwecke genutzt werden darf solange die Namen der Autoren (Julian Fietkau und Janina Nemec) als Urhebergenannt werden Weitere Infos httpcreativecommonsorglicensesby30Java ist ein eingetragenes Warenzeichen der Firma Sun Microsystems Inc
2
KurzfassungDieses Paper befasst sich mit der Umsetzung von zustandsbasiertem Verhalten
in der Programmiersprache Java Das Entwurfsmuster bdquoZustandldquo wird erklaumlrt undanhand eines Beispiels in mehreren Varianten in Java umgesetzt Weitere Moumlglichkei-ten der Umsetzung werden diskutiert insbesondere die Verwendung moderner Java-Sprachmittel in Abweichung vom strukturellen Entwurf des urspruumlnglichen Musters
1 EinfuumlhrungZustandsbasiertes Verhalten ist eines der zentralen Paradigmen die in der Beschreibungvon Hard- und Softwaresystemen zum Einsatz kommen Hierbei werden Entitaumlten (zBGeraumlte mit Mikroprozessoren ganze Softwareprogramme oder auch Objekte im OOP-Sinne) so programmiert dass sie eine bestimmte Menge an Zustaumlnden einnehmen koumlnnenzwischen denen sie auf einen Impuls hin wechseln Abhaumlngig davon in welchem Zustandsich eine Entitaumlt befindet kann sie ein spezielles Verhalten zeigenDieses zustandsbasierte Verhalten ist in der Softwareentwicklung immer wieder rele-
vant Deshalb gehen wir zum Einstieg auf einige typische Einsatzzwecke ein Im Anschlussgrenzen wir den Bereich des Themas ab mit dem wir uns in diesem Paper eingehendbeschaumlftigen
11 MotivationIn der theoretischen Informatik gibt es eine ganze Hierarchie von zustandsbasierten Mo-dellen die unterschiedlich maumlchtig sind Die Turing-Maschine ist etwa ein Modell dasneben einem einem Speicherband uumlber eine endliche Zustandsmenge verfuumlgt zwischendenen Wechsel stattfinden Der einfache endliche Zustandsautomat liest dagegen sequen-ziell seine Eingabedaten und wechselt dabei zwischen seinen Zustaumlnden Modelle wiediese sind in der Systemtheorie gaumlngige Mittel der Spezifikation Ebenso ist zustandsab-haumlngiges Verhalten ein intrinsisches Merkmal des Von-Neumann-Modells auf dem fastalle heute verbreiteten Rechnerarchitekturen aufbauenAls gaumlngiges Beispiel gilt das Netzwerkprotokoll TCP Dessen Spezifikation gibt das
erforderliche Verhalten der Kommunikationspartner teilweise als endliche Automaten anAufgrund der Verbreitung des Paradigmas stellt sich die Frage wie zustandsbasiertes
Verhalten in einer modernen objektorientierten Sprache sinnvoll umsetzbar ist Eineverbreitete und anerkannte Antwort auf diese Frage ist das Zustandsmuster welcheserstmalig von Gamma et al beschrieben und publiziert wurde (vgl [GHJV95])In diesem Paper wollen wir das Zustands-Entwurfsmuster in Bezug auf die Program-
miersprache Java analysieren und feststellen wie das Muster sich auf die modernenSprachmittel aktueller Java-Versionen uumlbertragen laumlsst Weiterhin wollen wir weitereMoumlglichkeiten untersuchen zustandsbasiertes Verhalten in Java umzusetzen
12 Thematische EingrenzungBei unseren Untersuchungen beschraumlnken wir uns auf Loumlsungsansaumltze fuumlr die Model-lierung zustandsbasierter Systeme in Java Die Umsetzung dieser Loumlsungen in anderen
3
Programmiersprachen oder gar unter anderen Programmierparadigmen als denen derObjektorientierung lassen wir auszligen vorWeil einige der beruumlhrten Themen fortgeschrittener Natur sind setzen wir fuumlr das
tiefgehende Verstaumlndnis dieses Papers zumindest solide Grundlagen in den folgendenBereichen voraus
bull Prinzipien der objektorientierten Modellierung
bull Grundidee und Zweck objektorientierter Entwurfsmuster
bull Umgang mit den Sprachmitteln von Java
Die Kenntnis gaumlngiger Zustandsautomaten-Modelle wie des endlichen Automaten kannweiterhin hilfreich sein
2 Ein einfaches zustandsbasiertes SystemIn der Praxis werden zustandsbasierte Systeme oft sehr komplex Mit steigenden Anfor-derungen muumlssen dann neue Zustaumlnde eingebaut und neues Verhalten entwickelt werdenDies bringt die Notwendigkeit mit sich saubere und flexible Methoden der Umsetzungdes Zustandsverhaltens zu beherrschenDennoch werden wir die verschiedenen Methoden in diesem Paper an einem einfachen
und uumlberschaubaren System demonstrieren Auch wenn damit die Vorteile der verschie-denen Methoden nicht so sehr ins Auge fallen sind wir der Meinung dass ein kleinesBeispiel der Verstaumlndlichkeit mehr nuumltzt als ein riesiges System mit einer groszligen Mengevon ZustaumlndenDie folgende Spezifikation beschreibt das Beispiel welches wir fuumlr dieses Paper ausge-
waumlhlt haben
Eine Lampe mit Kippschalter habe drei Zustaumlnde bdquoVolle Helligkeitldquo bdquoHalbeHelligkeitldquo und bdquoLicht ausldquo Es gibt zwei moumlgliche Aktionen fuumlr Klienten desSystems bdquoKippschalter links druumlckenldquo und bdquoKippschalter rechts druumlckenldquo (imFolgenden bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquo)Befindet sich der Kippschalter in der Mittelstellung so hat die Lampe den
Zustand bdquoLicht ausldquo Die Aktion bdquodruumlcke linksldquo fuumlhrt dann zu einem Zustands-wechsel nach bdquoVolle Helligkeitldquo bdquodruumlcke rechtsldquo analog nach bdquoHalbe HelligkeitldquoIm Zustand bdquoVolle Helligkeitldquo bewirkt die Aktion bdquodruumlcke linksldquo nichts
bdquodruumlcke rechtsldquo fuumlhrt zu einem Zustandswechsel nach bdquoLicht ausldquo Analoges giltfuumlr den Zustand bdquoHalbe Helligkeitldquo bdquodruumlcke rechtsldquo fuumlhrt zu keinem Zustands-uumlbergang und bdquodruumlcke linksldquo zu einem Zustandswechsel nach bdquoLicht ausldquoDie aktuelle Helligkeit der Lampe kann als Zahl zwischen 00 und 10 abgefragt
werden Im Zustand bdquoLicht ausldquo liegt sie bei 00 im Zustand bdquoHalbe Helligkeitldquobei 05 und im Zustand bdquoVolle Helligkeitldquo bei 10Bei Inbetriebnahme des Systems ist bdquoLicht ausldquo der Startzustand
4
Abbildung 1 Schematische Darstellung des Kippschalters im Zustand bdquoHalbe Helligkeitldquo
Licht aus
druumlcke rechts
druuml
cke
links
druuml
cke rech
ts
HalbeHelligkeit
VolleHelligkeit
druumlcke rechts
druumlcke links druumlcke links
Abbildung 2 Zustandsdiagramm des Lichtschalters
Der genannte Kippschalter ist ein gaumlngiger 3-Positionen-Kippschalter mit entsprechen-den Markierungen (Abbildung 1)Diese Spezifikation laumlsst sich nicht nur in Textform sondern auch zB als aumlquivalentes
Zustandsdiagramm ausdruumlcken (Abbildung 2)In den nun folgenden Abschnitten wollen wir einige Moumlglichkeiten erlaumlutern diese
Spezifikation in Java zu modellieren Dabei werden wir die verschiedenen Ansaumltze aufKriterien wie Fehleranfaumllligkeit und Erweiterbarkeit untersuchen
3 Loumlsungsansatz 1 Die naive UmsetzungDieser erste Ansatz entspricht der intuitiven Herangehensweise Es ist die Loumlsung dienormalerweise entsteht wenn keine bewusste Entscheidung fuumlr eine bestimmte Umset-zung von zustandsbasiertem Verhalten gefallen ist
31 EntwurfHierbei wird der aktuelle Zustand der Lampe in einem einfachen Zustandsfeld gehaltenIm verbreitetsten Fall waumlhlt die implementierende Person dafuumlr den Typ int mit
der Begruumlndung dass boolean nur zwei moumlgliche Werte hat wogegen im vorliegendenFall drei gebraucht werden Die aktuelle Helligkeit der Lampe wird dann bei Bedarfermittelt indem jedem Zustand eine Helligkeit zugewiesen wird Dazu dient haumlufig einswitch-Konstrukt Eine solche Modellierung kann programmiert etwa dem Code vonListing 1 entsprechen
5
Etwas sauberer und weniger fehleranfaumlllig laumlsst der Code sich gestalten indem statteines Zustandsfelds vom Typ int ein privater innerer Aufzaumlhlungstyp verwendet wirdDiese Verbesserung loumlst einige der Probleme des Entwurfs jedoch bei weitem nicht alleDieser Ansatz ist in Listing 2 umgesetzt
32 EigenschaftenDieser Entwurf entspricht der verbreiteten intuitiven Herangehensweise und ist deshalbin den meisten Faumlllen auch ohne Kenntnis irgendwelcher Entwurfsmuster sofort ver-staumlndlichNegativ faumlllt auf dass die Spezifikation der Zustaumlnde von der des zustandsabhaumlngigen
Verhaltens vergleichsweise weit entfernt ist Wuumlrde weiteres zustandsabhaumlngiges Verhal-ten neben der gibHelligkeit-Methode noumltig werden so muumlssten an mehreren Stellen inder Klasse alle Zustaumlnde und ihr jeweiliges spezifisches Verhalten aufgezaumlhlt werdenDas ist ein deutliches Zeichen fuumlr niedrige Kohaumlsion und laumluft anerkannten Designprin-
zipien zuwider Durch die immer wieder noumltige Aufzaumlhlung der Zustaumlnde wird die War-tung bei veraumlnderten Anforderungen stark erschwertBei der Variante mit einer int-Variable kommt eine gesteigerte Fehleranfaumllligkeit hin-
zu Durch Programmierfehler kann das Zustandsfeld einen unguumlltigen Wert annehmenwas undefinierte Konsequenzen haben kann Um das zu verhindern muss an allen Stel-len an denen der Zustand abgefragt wird auf eventuelle fehlerhafte Werte reagiert wer-den (in unserem Beispiel in Listing 1 wurde darauf geachtet) Wird ein Aufzaumlhlungstypverwendet wird diese komplette Fehlerklasse ausgeschlossen
Zusammenfassung
+ intuitiv schnell erfassbar
minus niedrige Kohaumlsion
minus erschwerte Wart- und Erweiterbarkeit
minus (ohne Aufzaumlhlungstyp gesteigerte Anfaumllligkeit fuumlr Programmierfehler)
4 Loumlsungsansatz 2 Das ZustandsmusterBei Gamma et al findet sich ein alternativer Vorschlag fuumlr die Implementation von zu-standsbasierten Systemen (vgl [GHJV95]) Das Entwurfsmuster bdquoZustandldquo versucht mitobjektorientierten Mitteln die Zustaumlnde und ihr jeweiliges Verhalten besser zu kapselnund so die Kohaumlsion zu steigern und die Erweiterung zu erleichternDie abstrakte Beschreibung des Musters ist sehr allgemein gehalten und macht kei-
nen Gebrauch von Java-spezifischen Sprachfeatures Wir empfehlen zum Selbststudiumdie Aufbereitung des Themas durch Freeman et al welche das Muster anhand eineskonkreten Beispiels mit Java-Code erklaumlrt (vgl [FFBS04])
6
Context
State myState
request()
myStatehandle()
ltltabstractgtgt
State
handle()
ConcreteStateA
handle()
ConcreteStateB
handle()
Abbildung 3 Klassendiagramm des Zustandsmusters nach Gamma et al
41 Beschreibung des MustersDas Zustandsmuster (engl state pattern) auch bekannt als bdquoObjekte fuumlr Zustaumlndeldquo(engl objects for states) gehoumlrt zur Kategorie der Verhaltensmuster (engl behavioralpatterns) und ist eines der Muster der bdquoGang of Fourldquo Der Sinn des Zustandsmusters istes die Veraumlnderung des Zustandes eines Objekts durch die scheinbare Aumlnderung seinerKlasse darzustellen indem Teile des Codes der von dem Objekt ausgefuumlhrt wird zurLaufzeit austauschbar gemacht werdenMan kann dieses Entwurfsmuster prinzipiell uumlberall dort anwenden wo das Verhalten
eines Objekts sich abhaumlngig von seinem Zustand zur Laufzeit aumlndert Der Einsatz lohntsich insbesondere dann wenn in einer Klasse an vielen Stellen im Code die gleicheZustandsunterscheidung mittels if- oder switch-Konstrukten erfolgtDas Zustandsmuster besteht aus drei Teilen (vgl Abbildung 3)
1 Den Rahmen bildet eine Kontextklasse welche nach auszligen hin den fachlichen Ge-genstand modelliert und intern ein Exemplar einer Zustandsklasse haumllt
2 Weiterhin gibt es ein Interface oder eine abstrakte Klasse die vorgibt welche Ope-rationen von jedem konkreten Zustand implementiert werden muumlssen Des Weite-ren ermoumlglicht der dadurch definierte Typ es dem Kontext durch polymorpheZuweisungen zwischen den konkreten Zustaumlnden zu wechseln
3 Auszligerdem muumlssen mindestens eine (sinnvollerweise mehrere) konkrete Zustands-klassen existieren von denen jede fuumlr sich einen Zustand mit seinem Verhaltenimplementiert Dieser Zustand ist zumeist durch eine Anzahl von zustandsspe-zifischen Konstanten undoder einprogrammierte je nach Zustand verschiedeneAlgorithmen verkoumlrpert
7
42 EntwurfNimmt man das vorangegangene Beispiel des Kippschalters so kann man an der naivenUmsetzung erkennen dass durch die vielen notwendigen if-Abfragen (in anderen Bei-spielen auch switchcase-Konstrukte) der Quelltext langsam unuumlbersichtlich und kom-pliziert wird Um solche Abfragen zu vermeiden wird in diesem Muster jeder Zustanddurch eine eigene Klasse abgebildetBei unserem Beispiel sind das drei Zustandsklassen bdquoVolle Helligkeitldquo bdquoHalbe Hellig-
keitldquo und bdquoLicht ausldquo Nun sind diese Zustandsklassen prinzipbedingt nicht voumlllig un-terschiedlich Ihre Operationen bilden eine einheitliche Schnittstelle Deshalb definiertman ein Interface oder eine abstrakte Klasse welche die gemeinsamen Operationen derkonkreten Zustandsklassen vorgibtIn unseren Quelltextbeispielen (Listings 3 und 4) waumlre dies das Interface LampeZustand
Unsere konkreten Zustandsklassen sind entsprechend LampeZustandHalbeHelligkeit so-wie LampeZustandVolleHelligkeit und LampeZustandLichtAus Bei der Klasse Lampe
handelt es sich um eine sogenannte Kontextklasse welche die Zustandsklassen verwen-det Als Startzustand haumllt die Kontextklasse in einer Exemplarvariablen die Referenzauf ein Exemplar der vordefinierten Startzustandsklasse Diese Startzustandklasse isteine der konkreten Zustandsklassen Aumlndert sich der Zustand so wird die Referenz aufein Exemplar der entsprechenden neuen Zustandsklasse umgebogen Dadurch wird deraktuelle Zustand gespeichert In den Listings 3 und 4 waumlre das entsprechend die Variablezustand die zu Beginn ein Exemplar der Klasse LampeZustandLichtAus haumlltIm Zustandsmuster ist nicht vorgegeben wann Objekte erzeugt und zerstoumlrt werden
sollten Hierbei bieten sich zwei Moumlglichkeiten an
bull Eine Moumlglichkeit ist das Erzeugen des Zustandsobjektes bei Bedarf und die Zerstouml-rung bei Zustandsaumlnderung Diese Alternative laumlsst sich den meisten Auspraumlgungendes Zustandsmusters einfach realisieren
bull Dann gibt es noch die Option in der Kontextklasse ein Exemplar jeder Zustands-klasse zu erzeugen und die Referenzen zB in Exemplarvariablen zu speichern Nunfinden bei Zustandsuumlbergaumlngen Zuweisungen zur entsprechenden Variable stattBei dieser Moumlglichkeit werden die Objekte nie bzw erst am Ende der Ausfuumlhrungdes Programms zerstoumlrt
Die erste Alternative sollte man bevorzugen wenn noch nicht klar ist welche Zustaumlndezur Laufzeit benoumltigt werden und die Frequenz der Zustandsuumlbergaumlnge nicht sehr hochist Wechseln die Zustaumlnde jedoch haumlufig so sollte man eher die zweite Option umsetzenKoumlnnen mehrere Kontexte die gleichen Zustandsobjekte verwenden kann Speicher-
platz eingespart werden Solange die Zustandsklassen selbst keinen veraumlnderbaren Zu-stand besitzen ist das theoretisch moumlglich Es bringt jedoch auch die Gefahr mit sichdass eine unnoumltig enge Kopplung zwischen zwei verschiedenen Kontexten entstehtNun gibt das Zustandsmuster allerdings nicht vor welche Klasse oder Klassen die
Transitionsverwaltung zu uumlbernehmen haben Deshalb gibt es mehrere Moumlglichkeitenwelche Klassen die Transitionslogik beinhalten koumlnnen Welche der beiden Moumlglichkeiten
8
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
6 Weitere Ansaumltze 1361 Objektbasiertes Zustandsgeflecht 1362 Enum mit Transitionstabelle 14
7 Zusammenfassung 14
Anhang 16Quelltext-Listings 16
1 Naive Umsetzung 162 Naive Umsetzung mit innerem Aufzaumlhlungstyp 173 Zustandsmuster mit dezentraler Transitionsverwaltung 184 Zustandsmuster mit zentraler Transitionsverwaltung 205 Externer Zustand als Aufzaumlhlungstyp 226 Objektbasiertes Zustandsgeflecht 247 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle 26
Literatur 28
Dieses Werk steht unter der Creative Commons Attribution 30 Lizenz Das bedeutet dass es mit wenigen Einschraumlnkungen kopiertverteilt und fuumlr jegliche Zwecke genutzt werden darf solange die Namen der Autoren (Julian Fietkau und Janina Nemec) als Urhebergenannt werden Weitere Infos httpcreativecommonsorglicensesby30Java ist ein eingetragenes Warenzeichen der Firma Sun Microsystems Inc
2
KurzfassungDieses Paper befasst sich mit der Umsetzung von zustandsbasiertem Verhalten
in der Programmiersprache Java Das Entwurfsmuster bdquoZustandldquo wird erklaumlrt undanhand eines Beispiels in mehreren Varianten in Java umgesetzt Weitere Moumlglichkei-ten der Umsetzung werden diskutiert insbesondere die Verwendung moderner Java-Sprachmittel in Abweichung vom strukturellen Entwurf des urspruumlnglichen Musters
1 EinfuumlhrungZustandsbasiertes Verhalten ist eines der zentralen Paradigmen die in der Beschreibungvon Hard- und Softwaresystemen zum Einsatz kommen Hierbei werden Entitaumlten (zBGeraumlte mit Mikroprozessoren ganze Softwareprogramme oder auch Objekte im OOP-Sinne) so programmiert dass sie eine bestimmte Menge an Zustaumlnden einnehmen koumlnnenzwischen denen sie auf einen Impuls hin wechseln Abhaumlngig davon in welchem Zustandsich eine Entitaumlt befindet kann sie ein spezielles Verhalten zeigenDieses zustandsbasierte Verhalten ist in der Softwareentwicklung immer wieder rele-
vant Deshalb gehen wir zum Einstieg auf einige typische Einsatzzwecke ein Im Anschlussgrenzen wir den Bereich des Themas ab mit dem wir uns in diesem Paper eingehendbeschaumlftigen
11 MotivationIn der theoretischen Informatik gibt es eine ganze Hierarchie von zustandsbasierten Mo-dellen die unterschiedlich maumlchtig sind Die Turing-Maschine ist etwa ein Modell dasneben einem einem Speicherband uumlber eine endliche Zustandsmenge verfuumlgt zwischendenen Wechsel stattfinden Der einfache endliche Zustandsautomat liest dagegen sequen-ziell seine Eingabedaten und wechselt dabei zwischen seinen Zustaumlnden Modelle wiediese sind in der Systemtheorie gaumlngige Mittel der Spezifikation Ebenso ist zustandsab-haumlngiges Verhalten ein intrinsisches Merkmal des Von-Neumann-Modells auf dem fastalle heute verbreiteten Rechnerarchitekturen aufbauenAls gaumlngiges Beispiel gilt das Netzwerkprotokoll TCP Dessen Spezifikation gibt das
erforderliche Verhalten der Kommunikationspartner teilweise als endliche Automaten anAufgrund der Verbreitung des Paradigmas stellt sich die Frage wie zustandsbasiertes
Verhalten in einer modernen objektorientierten Sprache sinnvoll umsetzbar ist Eineverbreitete und anerkannte Antwort auf diese Frage ist das Zustandsmuster welcheserstmalig von Gamma et al beschrieben und publiziert wurde (vgl [GHJV95])In diesem Paper wollen wir das Zustands-Entwurfsmuster in Bezug auf die Program-
miersprache Java analysieren und feststellen wie das Muster sich auf die modernenSprachmittel aktueller Java-Versionen uumlbertragen laumlsst Weiterhin wollen wir weitereMoumlglichkeiten untersuchen zustandsbasiertes Verhalten in Java umzusetzen
12 Thematische EingrenzungBei unseren Untersuchungen beschraumlnken wir uns auf Loumlsungsansaumltze fuumlr die Model-lierung zustandsbasierter Systeme in Java Die Umsetzung dieser Loumlsungen in anderen
3
Programmiersprachen oder gar unter anderen Programmierparadigmen als denen derObjektorientierung lassen wir auszligen vorWeil einige der beruumlhrten Themen fortgeschrittener Natur sind setzen wir fuumlr das
tiefgehende Verstaumlndnis dieses Papers zumindest solide Grundlagen in den folgendenBereichen voraus
bull Prinzipien der objektorientierten Modellierung
bull Grundidee und Zweck objektorientierter Entwurfsmuster
bull Umgang mit den Sprachmitteln von Java
Die Kenntnis gaumlngiger Zustandsautomaten-Modelle wie des endlichen Automaten kannweiterhin hilfreich sein
2 Ein einfaches zustandsbasiertes SystemIn der Praxis werden zustandsbasierte Systeme oft sehr komplex Mit steigenden Anfor-derungen muumlssen dann neue Zustaumlnde eingebaut und neues Verhalten entwickelt werdenDies bringt die Notwendigkeit mit sich saubere und flexible Methoden der Umsetzungdes Zustandsverhaltens zu beherrschenDennoch werden wir die verschiedenen Methoden in diesem Paper an einem einfachen
und uumlberschaubaren System demonstrieren Auch wenn damit die Vorteile der verschie-denen Methoden nicht so sehr ins Auge fallen sind wir der Meinung dass ein kleinesBeispiel der Verstaumlndlichkeit mehr nuumltzt als ein riesiges System mit einer groszligen Mengevon ZustaumlndenDie folgende Spezifikation beschreibt das Beispiel welches wir fuumlr dieses Paper ausge-
waumlhlt haben
Eine Lampe mit Kippschalter habe drei Zustaumlnde bdquoVolle Helligkeitldquo bdquoHalbeHelligkeitldquo und bdquoLicht ausldquo Es gibt zwei moumlgliche Aktionen fuumlr Klienten desSystems bdquoKippschalter links druumlckenldquo und bdquoKippschalter rechts druumlckenldquo (imFolgenden bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquo)Befindet sich der Kippschalter in der Mittelstellung so hat die Lampe den
Zustand bdquoLicht ausldquo Die Aktion bdquodruumlcke linksldquo fuumlhrt dann zu einem Zustands-wechsel nach bdquoVolle Helligkeitldquo bdquodruumlcke rechtsldquo analog nach bdquoHalbe HelligkeitldquoIm Zustand bdquoVolle Helligkeitldquo bewirkt die Aktion bdquodruumlcke linksldquo nichts
bdquodruumlcke rechtsldquo fuumlhrt zu einem Zustandswechsel nach bdquoLicht ausldquo Analoges giltfuumlr den Zustand bdquoHalbe Helligkeitldquo bdquodruumlcke rechtsldquo fuumlhrt zu keinem Zustands-uumlbergang und bdquodruumlcke linksldquo zu einem Zustandswechsel nach bdquoLicht ausldquoDie aktuelle Helligkeit der Lampe kann als Zahl zwischen 00 und 10 abgefragt
werden Im Zustand bdquoLicht ausldquo liegt sie bei 00 im Zustand bdquoHalbe Helligkeitldquobei 05 und im Zustand bdquoVolle Helligkeitldquo bei 10Bei Inbetriebnahme des Systems ist bdquoLicht ausldquo der Startzustand
4
Abbildung 1 Schematische Darstellung des Kippschalters im Zustand bdquoHalbe Helligkeitldquo
Licht aus
druumlcke rechts
druuml
cke
links
druuml
cke rech
ts
HalbeHelligkeit
VolleHelligkeit
druumlcke rechts
druumlcke links druumlcke links
Abbildung 2 Zustandsdiagramm des Lichtschalters
Der genannte Kippschalter ist ein gaumlngiger 3-Positionen-Kippschalter mit entsprechen-den Markierungen (Abbildung 1)Diese Spezifikation laumlsst sich nicht nur in Textform sondern auch zB als aumlquivalentes
Zustandsdiagramm ausdruumlcken (Abbildung 2)In den nun folgenden Abschnitten wollen wir einige Moumlglichkeiten erlaumlutern diese
Spezifikation in Java zu modellieren Dabei werden wir die verschiedenen Ansaumltze aufKriterien wie Fehleranfaumllligkeit und Erweiterbarkeit untersuchen
3 Loumlsungsansatz 1 Die naive UmsetzungDieser erste Ansatz entspricht der intuitiven Herangehensweise Es ist die Loumlsung dienormalerweise entsteht wenn keine bewusste Entscheidung fuumlr eine bestimmte Umset-zung von zustandsbasiertem Verhalten gefallen ist
31 EntwurfHierbei wird der aktuelle Zustand der Lampe in einem einfachen Zustandsfeld gehaltenIm verbreitetsten Fall waumlhlt die implementierende Person dafuumlr den Typ int mit
der Begruumlndung dass boolean nur zwei moumlgliche Werte hat wogegen im vorliegendenFall drei gebraucht werden Die aktuelle Helligkeit der Lampe wird dann bei Bedarfermittelt indem jedem Zustand eine Helligkeit zugewiesen wird Dazu dient haumlufig einswitch-Konstrukt Eine solche Modellierung kann programmiert etwa dem Code vonListing 1 entsprechen
5
Etwas sauberer und weniger fehleranfaumlllig laumlsst der Code sich gestalten indem statteines Zustandsfelds vom Typ int ein privater innerer Aufzaumlhlungstyp verwendet wirdDiese Verbesserung loumlst einige der Probleme des Entwurfs jedoch bei weitem nicht alleDieser Ansatz ist in Listing 2 umgesetzt
32 EigenschaftenDieser Entwurf entspricht der verbreiteten intuitiven Herangehensweise und ist deshalbin den meisten Faumlllen auch ohne Kenntnis irgendwelcher Entwurfsmuster sofort ver-staumlndlichNegativ faumlllt auf dass die Spezifikation der Zustaumlnde von der des zustandsabhaumlngigen
Verhaltens vergleichsweise weit entfernt ist Wuumlrde weiteres zustandsabhaumlngiges Verhal-ten neben der gibHelligkeit-Methode noumltig werden so muumlssten an mehreren Stellen inder Klasse alle Zustaumlnde und ihr jeweiliges spezifisches Verhalten aufgezaumlhlt werdenDas ist ein deutliches Zeichen fuumlr niedrige Kohaumlsion und laumluft anerkannten Designprin-
zipien zuwider Durch die immer wieder noumltige Aufzaumlhlung der Zustaumlnde wird die War-tung bei veraumlnderten Anforderungen stark erschwertBei der Variante mit einer int-Variable kommt eine gesteigerte Fehleranfaumllligkeit hin-
zu Durch Programmierfehler kann das Zustandsfeld einen unguumlltigen Wert annehmenwas undefinierte Konsequenzen haben kann Um das zu verhindern muss an allen Stel-len an denen der Zustand abgefragt wird auf eventuelle fehlerhafte Werte reagiert wer-den (in unserem Beispiel in Listing 1 wurde darauf geachtet) Wird ein Aufzaumlhlungstypverwendet wird diese komplette Fehlerklasse ausgeschlossen
Zusammenfassung
+ intuitiv schnell erfassbar
minus niedrige Kohaumlsion
minus erschwerte Wart- und Erweiterbarkeit
minus (ohne Aufzaumlhlungstyp gesteigerte Anfaumllligkeit fuumlr Programmierfehler)
4 Loumlsungsansatz 2 Das ZustandsmusterBei Gamma et al findet sich ein alternativer Vorschlag fuumlr die Implementation von zu-standsbasierten Systemen (vgl [GHJV95]) Das Entwurfsmuster bdquoZustandldquo versucht mitobjektorientierten Mitteln die Zustaumlnde und ihr jeweiliges Verhalten besser zu kapselnund so die Kohaumlsion zu steigern und die Erweiterung zu erleichternDie abstrakte Beschreibung des Musters ist sehr allgemein gehalten und macht kei-
nen Gebrauch von Java-spezifischen Sprachfeatures Wir empfehlen zum Selbststudiumdie Aufbereitung des Themas durch Freeman et al welche das Muster anhand eineskonkreten Beispiels mit Java-Code erklaumlrt (vgl [FFBS04])
6
Context
State myState
request()
myStatehandle()
ltltabstractgtgt
State
handle()
ConcreteStateA
handle()
ConcreteStateB
handle()
Abbildung 3 Klassendiagramm des Zustandsmusters nach Gamma et al
41 Beschreibung des MustersDas Zustandsmuster (engl state pattern) auch bekannt als bdquoObjekte fuumlr Zustaumlndeldquo(engl objects for states) gehoumlrt zur Kategorie der Verhaltensmuster (engl behavioralpatterns) und ist eines der Muster der bdquoGang of Fourldquo Der Sinn des Zustandsmusters istes die Veraumlnderung des Zustandes eines Objekts durch die scheinbare Aumlnderung seinerKlasse darzustellen indem Teile des Codes der von dem Objekt ausgefuumlhrt wird zurLaufzeit austauschbar gemacht werdenMan kann dieses Entwurfsmuster prinzipiell uumlberall dort anwenden wo das Verhalten
eines Objekts sich abhaumlngig von seinem Zustand zur Laufzeit aumlndert Der Einsatz lohntsich insbesondere dann wenn in einer Klasse an vielen Stellen im Code die gleicheZustandsunterscheidung mittels if- oder switch-Konstrukten erfolgtDas Zustandsmuster besteht aus drei Teilen (vgl Abbildung 3)
1 Den Rahmen bildet eine Kontextklasse welche nach auszligen hin den fachlichen Ge-genstand modelliert und intern ein Exemplar einer Zustandsklasse haumllt
2 Weiterhin gibt es ein Interface oder eine abstrakte Klasse die vorgibt welche Ope-rationen von jedem konkreten Zustand implementiert werden muumlssen Des Weite-ren ermoumlglicht der dadurch definierte Typ es dem Kontext durch polymorpheZuweisungen zwischen den konkreten Zustaumlnden zu wechseln
3 Auszligerdem muumlssen mindestens eine (sinnvollerweise mehrere) konkrete Zustands-klassen existieren von denen jede fuumlr sich einen Zustand mit seinem Verhaltenimplementiert Dieser Zustand ist zumeist durch eine Anzahl von zustandsspe-zifischen Konstanten undoder einprogrammierte je nach Zustand verschiedeneAlgorithmen verkoumlrpert
7
42 EntwurfNimmt man das vorangegangene Beispiel des Kippschalters so kann man an der naivenUmsetzung erkennen dass durch die vielen notwendigen if-Abfragen (in anderen Bei-spielen auch switchcase-Konstrukte) der Quelltext langsam unuumlbersichtlich und kom-pliziert wird Um solche Abfragen zu vermeiden wird in diesem Muster jeder Zustanddurch eine eigene Klasse abgebildetBei unserem Beispiel sind das drei Zustandsklassen bdquoVolle Helligkeitldquo bdquoHalbe Hellig-
keitldquo und bdquoLicht ausldquo Nun sind diese Zustandsklassen prinzipbedingt nicht voumlllig un-terschiedlich Ihre Operationen bilden eine einheitliche Schnittstelle Deshalb definiertman ein Interface oder eine abstrakte Klasse welche die gemeinsamen Operationen derkonkreten Zustandsklassen vorgibtIn unseren Quelltextbeispielen (Listings 3 und 4) waumlre dies das Interface LampeZustand
Unsere konkreten Zustandsklassen sind entsprechend LampeZustandHalbeHelligkeit so-wie LampeZustandVolleHelligkeit und LampeZustandLichtAus Bei der Klasse Lampe
handelt es sich um eine sogenannte Kontextklasse welche die Zustandsklassen verwen-det Als Startzustand haumllt die Kontextklasse in einer Exemplarvariablen die Referenzauf ein Exemplar der vordefinierten Startzustandsklasse Diese Startzustandklasse isteine der konkreten Zustandsklassen Aumlndert sich der Zustand so wird die Referenz aufein Exemplar der entsprechenden neuen Zustandsklasse umgebogen Dadurch wird deraktuelle Zustand gespeichert In den Listings 3 und 4 waumlre das entsprechend die Variablezustand die zu Beginn ein Exemplar der Klasse LampeZustandLichtAus haumlltIm Zustandsmuster ist nicht vorgegeben wann Objekte erzeugt und zerstoumlrt werden
sollten Hierbei bieten sich zwei Moumlglichkeiten an
bull Eine Moumlglichkeit ist das Erzeugen des Zustandsobjektes bei Bedarf und die Zerstouml-rung bei Zustandsaumlnderung Diese Alternative laumlsst sich den meisten Auspraumlgungendes Zustandsmusters einfach realisieren
bull Dann gibt es noch die Option in der Kontextklasse ein Exemplar jeder Zustands-klasse zu erzeugen und die Referenzen zB in Exemplarvariablen zu speichern Nunfinden bei Zustandsuumlbergaumlngen Zuweisungen zur entsprechenden Variable stattBei dieser Moumlglichkeit werden die Objekte nie bzw erst am Ende der Ausfuumlhrungdes Programms zerstoumlrt
Die erste Alternative sollte man bevorzugen wenn noch nicht klar ist welche Zustaumlndezur Laufzeit benoumltigt werden und die Frequenz der Zustandsuumlbergaumlnge nicht sehr hochist Wechseln die Zustaumlnde jedoch haumlufig so sollte man eher die zweite Option umsetzenKoumlnnen mehrere Kontexte die gleichen Zustandsobjekte verwenden kann Speicher-
platz eingespart werden Solange die Zustandsklassen selbst keinen veraumlnderbaren Zu-stand besitzen ist das theoretisch moumlglich Es bringt jedoch auch die Gefahr mit sichdass eine unnoumltig enge Kopplung zwischen zwei verschiedenen Kontexten entstehtNun gibt das Zustandsmuster allerdings nicht vor welche Klasse oder Klassen die
Transitionsverwaltung zu uumlbernehmen haben Deshalb gibt es mehrere Moumlglichkeitenwelche Klassen die Transitionslogik beinhalten koumlnnen Welche der beiden Moumlglichkeiten
8
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
KurzfassungDieses Paper befasst sich mit der Umsetzung von zustandsbasiertem Verhalten
in der Programmiersprache Java Das Entwurfsmuster bdquoZustandldquo wird erklaumlrt undanhand eines Beispiels in mehreren Varianten in Java umgesetzt Weitere Moumlglichkei-ten der Umsetzung werden diskutiert insbesondere die Verwendung moderner Java-Sprachmittel in Abweichung vom strukturellen Entwurf des urspruumlnglichen Musters
1 EinfuumlhrungZustandsbasiertes Verhalten ist eines der zentralen Paradigmen die in der Beschreibungvon Hard- und Softwaresystemen zum Einsatz kommen Hierbei werden Entitaumlten (zBGeraumlte mit Mikroprozessoren ganze Softwareprogramme oder auch Objekte im OOP-Sinne) so programmiert dass sie eine bestimmte Menge an Zustaumlnden einnehmen koumlnnenzwischen denen sie auf einen Impuls hin wechseln Abhaumlngig davon in welchem Zustandsich eine Entitaumlt befindet kann sie ein spezielles Verhalten zeigenDieses zustandsbasierte Verhalten ist in der Softwareentwicklung immer wieder rele-
vant Deshalb gehen wir zum Einstieg auf einige typische Einsatzzwecke ein Im Anschlussgrenzen wir den Bereich des Themas ab mit dem wir uns in diesem Paper eingehendbeschaumlftigen
11 MotivationIn der theoretischen Informatik gibt es eine ganze Hierarchie von zustandsbasierten Mo-dellen die unterschiedlich maumlchtig sind Die Turing-Maschine ist etwa ein Modell dasneben einem einem Speicherband uumlber eine endliche Zustandsmenge verfuumlgt zwischendenen Wechsel stattfinden Der einfache endliche Zustandsautomat liest dagegen sequen-ziell seine Eingabedaten und wechselt dabei zwischen seinen Zustaumlnden Modelle wiediese sind in der Systemtheorie gaumlngige Mittel der Spezifikation Ebenso ist zustandsab-haumlngiges Verhalten ein intrinsisches Merkmal des Von-Neumann-Modells auf dem fastalle heute verbreiteten Rechnerarchitekturen aufbauenAls gaumlngiges Beispiel gilt das Netzwerkprotokoll TCP Dessen Spezifikation gibt das
erforderliche Verhalten der Kommunikationspartner teilweise als endliche Automaten anAufgrund der Verbreitung des Paradigmas stellt sich die Frage wie zustandsbasiertes
Verhalten in einer modernen objektorientierten Sprache sinnvoll umsetzbar ist Eineverbreitete und anerkannte Antwort auf diese Frage ist das Zustandsmuster welcheserstmalig von Gamma et al beschrieben und publiziert wurde (vgl [GHJV95])In diesem Paper wollen wir das Zustands-Entwurfsmuster in Bezug auf die Program-
miersprache Java analysieren und feststellen wie das Muster sich auf die modernenSprachmittel aktueller Java-Versionen uumlbertragen laumlsst Weiterhin wollen wir weitereMoumlglichkeiten untersuchen zustandsbasiertes Verhalten in Java umzusetzen
12 Thematische EingrenzungBei unseren Untersuchungen beschraumlnken wir uns auf Loumlsungsansaumltze fuumlr die Model-lierung zustandsbasierter Systeme in Java Die Umsetzung dieser Loumlsungen in anderen
3
Programmiersprachen oder gar unter anderen Programmierparadigmen als denen derObjektorientierung lassen wir auszligen vorWeil einige der beruumlhrten Themen fortgeschrittener Natur sind setzen wir fuumlr das
tiefgehende Verstaumlndnis dieses Papers zumindest solide Grundlagen in den folgendenBereichen voraus
bull Prinzipien der objektorientierten Modellierung
bull Grundidee und Zweck objektorientierter Entwurfsmuster
bull Umgang mit den Sprachmitteln von Java
Die Kenntnis gaumlngiger Zustandsautomaten-Modelle wie des endlichen Automaten kannweiterhin hilfreich sein
2 Ein einfaches zustandsbasiertes SystemIn der Praxis werden zustandsbasierte Systeme oft sehr komplex Mit steigenden Anfor-derungen muumlssen dann neue Zustaumlnde eingebaut und neues Verhalten entwickelt werdenDies bringt die Notwendigkeit mit sich saubere und flexible Methoden der Umsetzungdes Zustandsverhaltens zu beherrschenDennoch werden wir die verschiedenen Methoden in diesem Paper an einem einfachen
und uumlberschaubaren System demonstrieren Auch wenn damit die Vorteile der verschie-denen Methoden nicht so sehr ins Auge fallen sind wir der Meinung dass ein kleinesBeispiel der Verstaumlndlichkeit mehr nuumltzt als ein riesiges System mit einer groszligen Mengevon ZustaumlndenDie folgende Spezifikation beschreibt das Beispiel welches wir fuumlr dieses Paper ausge-
waumlhlt haben
Eine Lampe mit Kippschalter habe drei Zustaumlnde bdquoVolle Helligkeitldquo bdquoHalbeHelligkeitldquo und bdquoLicht ausldquo Es gibt zwei moumlgliche Aktionen fuumlr Klienten desSystems bdquoKippschalter links druumlckenldquo und bdquoKippschalter rechts druumlckenldquo (imFolgenden bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquo)Befindet sich der Kippschalter in der Mittelstellung so hat die Lampe den
Zustand bdquoLicht ausldquo Die Aktion bdquodruumlcke linksldquo fuumlhrt dann zu einem Zustands-wechsel nach bdquoVolle Helligkeitldquo bdquodruumlcke rechtsldquo analog nach bdquoHalbe HelligkeitldquoIm Zustand bdquoVolle Helligkeitldquo bewirkt die Aktion bdquodruumlcke linksldquo nichts
bdquodruumlcke rechtsldquo fuumlhrt zu einem Zustandswechsel nach bdquoLicht ausldquo Analoges giltfuumlr den Zustand bdquoHalbe Helligkeitldquo bdquodruumlcke rechtsldquo fuumlhrt zu keinem Zustands-uumlbergang und bdquodruumlcke linksldquo zu einem Zustandswechsel nach bdquoLicht ausldquoDie aktuelle Helligkeit der Lampe kann als Zahl zwischen 00 und 10 abgefragt
werden Im Zustand bdquoLicht ausldquo liegt sie bei 00 im Zustand bdquoHalbe Helligkeitldquobei 05 und im Zustand bdquoVolle Helligkeitldquo bei 10Bei Inbetriebnahme des Systems ist bdquoLicht ausldquo der Startzustand
4
Abbildung 1 Schematische Darstellung des Kippschalters im Zustand bdquoHalbe Helligkeitldquo
Licht aus
druumlcke rechts
druuml
cke
links
druuml
cke rech
ts
HalbeHelligkeit
VolleHelligkeit
druumlcke rechts
druumlcke links druumlcke links
Abbildung 2 Zustandsdiagramm des Lichtschalters
Der genannte Kippschalter ist ein gaumlngiger 3-Positionen-Kippschalter mit entsprechen-den Markierungen (Abbildung 1)Diese Spezifikation laumlsst sich nicht nur in Textform sondern auch zB als aumlquivalentes
Zustandsdiagramm ausdruumlcken (Abbildung 2)In den nun folgenden Abschnitten wollen wir einige Moumlglichkeiten erlaumlutern diese
Spezifikation in Java zu modellieren Dabei werden wir die verschiedenen Ansaumltze aufKriterien wie Fehleranfaumllligkeit und Erweiterbarkeit untersuchen
3 Loumlsungsansatz 1 Die naive UmsetzungDieser erste Ansatz entspricht der intuitiven Herangehensweise Es ist die Loumlsung dienormalerweise entsteht wenn keine bewusste Entscheidung fuumlr eine bestimmte Umset-zung von zustandsbasiertem Verhalten gefallen ist
31 EntwurfHierbei wird der aktuelle Zustand der Lampe in einem einfachen Zustandsfeld gehaltenIm verbreitetsten Fall waumlhlt die implementierende Person dafuumlr den Typ int mit
der Begruumlndung dass boolean nur zwei moumlgliche Werte hat wogegen im vorliegendenFall drei gebraucht werden Die aktuelle Helligkeit der Lampe wird dann bei Bedarfermittelt indem jedem Zustand eine Helligkeit zugewiesen wird Dazu dient haumlufig einswitch-Konstrukt Eine solche Modellierung kann programmiert etwa dem Code vonListing 1 entsprechen
5
Etwas sauberer und weniger fehleranfaumlllig laumlsst der Code sich gestalten indem statteines Zustandsfelds vom Typ int ein privater innerer Aufzaumlhlungstyp verwendet wirdDiese Verbesserung loumlst einige der Probleme des Entwurfs jedoch bei weitem nicht alleDieser Ansatz ist in Listing 2 umgesetzt
32 EigenschaftenDieser Entwurf entspricht der verbreiteten intuitiven Herangehensweise und ist deshalbin den meisten Faumlllen auch ohne Kenntnis irgendwelcher Entwurfsmuster sofort ver-staumlndlichNegativ faumlllt auf dass die Spezifikation der Zustaumlnde von der des zustandsabhaumlngigen
Verhaltens vergleichsweise weit entfernt ist Wuumlrde weiteres zustandsabhaumlngiges Verhal-ten neben der gibHelligkeit-Methode noumltig werden so muumlssten an mehreren Stellen inder Klasse alle Zustaumlnde und ihr jeweiliges spezifisches Verhalten aufgezaumlhlt werdenDas ist ein deutliches Zeichen fuumlr niedrige Kohaumlsion und laumluft anerkannten Designprin-
zipien zuwider Durch die immer wieder noumltige Aufzaumlhlung der Zustaumlnde wird die War-tung bei veraumlnderten Anforderungen stark erschwertBei der Variante mit einer int-Variable kommt eine gesteigerte Fehleranfaumllligkeit hin-
zu Durch Programmierfehler kann das Zustandsfeld einen unguumlltigen Wert annehmenwas undefinierte Konsequenzen haben kann Um das zu verhindern muss an allen Stel-len an denen der Zustand abgefragt wird auf eventuelle fehlerhafte Werte reagiert wer-den (in unserem Beispiel in Listing 1 wurde darauf geachtet) Wird ein Aufzaumlhlungstypverwendet wird diese komplette Fehlerklasse ausgeschlossen
Zusammenfassung
+ intuitiv schnell erfassbar
minus niedrige Kohaumlsion
minus erschwerte Wart- und Erweiterbarkeit
minus (ohne Aufzaumlhlungstyp gesteigerte Anfaumllligkeit fuumlr Programmierfehler)
4 Loumlsungsansatz 2 Das ZustandsmusterBei Gamma et al findet sich ein alternativer Vorschlag fuumlr die Implementation von zu-standsbasierten Systemen (vgl [GHJV95]) Das Entwurfsmuster bdquoZustandldquo versucht mitobjektorientierten Mitteln die Zustaumlnde und ihr jeweiliges Verhalten besser zu kapselnund so die Kohaumlsion zu steigern und die Erweiterung zu erleichternDie abstrakte Beschreibung des Musters ist sehr allgemein gehalten und macht kei-
nen Gebrauch von Java-spezifischen Sprachfeatures Wir empfehlen zum Selbststudiumdie Aufbereitung des Themas durch Freeman et al welche das Muster anhand eineskonkreten Beispiels mit Java-Code erklaumlrt (vgl [FFBS04])
6
Context
State myState
request()
myStatehandle()
ltltabstractgtgt
State
handle()
ConcreteStateA
handle()
ConcreteStateB
handle()
Abbildung 3 Klassendiagramm des Zustandsmusters nach Gamma et al
41 Beschreibung des MustersDas Zustandsmuster (engl state pattern) auch bekannt als bdquoObjekte fuumlr Zustaumlndeldquo(engl objects for states) gehoumlrt zur Kategorie der Verhaltensmuster (engl behavioralpatterns) und ist eines der Muster der bdquoGang of Fourldquo Der Sinn des Zustandsmusters istes die Veraumlnderung des Zustandes eines Objekts durch die scheinbare Aumlnderung seinerKlasse darzustellen indem Teile des Codes der von dem Objekt ausgefuumlhrt wird zurLaufzeit austauschbar gemacht werdenMan kann dieses Entwurfsmuster prinzipiell uumlberall dort anwenden wo das Verhalten
eines Objekts sich abhaumlngig von seinem Zustand zur Laufzeit aumlndert Der Einsatz lohntsich insbesondere dann wenn in einer Klasse an vielen Stellen im Code die gleicheZustandsunterscheidung mittels if- oder switch-Konstrukten erfolgtDas Zustandsmuster besteht aus drei Teilen (vgl Abbildung 3)
1 Den Rahmen bildet eine Kontextklasse welche nach auszligen hin den fachlichen Ge-genstand modelliert und intern ein Exemplar einer Zustandsklasse haumllt
2 Weiterhin gibt es ein Interface oder eine abstrakte Klasse die vorgibt welche Ope-rationen von jedem konkreten Zustand implementiert werden muumlssen Des Weite-ren ermoumlglicht der dadurch definierte Typ es dem Kontext durch polymorpheZuweisungen zwischen den konkreten Zustaumlnden zu wechseln
3 Auszligerdem muumlssen mindestens eine (sinnvollerweise mehrere) konkrete Zustands-klassen existieren von denen jede fuumlr sich einen Zustand mit seinem Verhaltenimplementiert Dieser Zustand ist zumeist durch eine Anzahl von zustandsspe-zifischen Konstanten undoder einprogrammierte je nach Zustand verschiedeneAlgorithmen verkoumlrpert
7
42 EntwurfNimmt man das vorangegangene Beispiel des Kippschalters so kann man an der naivenUmsetzung erkennen dass durch die vielen notwendigen if-Abfragen (in anderen Bei-spielen auch switchcase-Konstrukte) der Quelltext langsam unuumlbersichtlich und kom-pliziert wird Um solche Abfragen zu vermeiden wird in diesem Muster jeder Zustanddurch eine eigene Klasse abgebildetBei unserem Beispiel sind das drei Zustandsklassen bdquoVolle Helligkeitldquo bdquoHalbe Hellig-
keitldquo und bdquoLicht ausldquo Nun sind diese Zustandsklassen prinzipbedingt nicht voumlllig un-terschiedlich Ihre Operationen bilden eine einheitliche Schnittstelle Deshalb definiertman ein Interface oder eine abstrakte Klasse welche die gemeinsamen Operationen derkonkreten Zustandsklassen vorgibtIn unseren Quelltextbeispielen (Listings 3 und 4) waumlre dies das Interface LampeZustand
Unsere konkreten Zustandsklassen sind entsprechend LampeZustandHalbeHelligkeit so-wie LampeZustandVolleHelligkeit und LampeZustandLichtAus Bei der Klasse Lampe
handelt es sich um eine sogenannte Kontextklasse welche die Zustandsklassen verwen-det Als Startzustand haumllt die Kontextklasse in einer Exemplarvariablen die Referenzauf ein Exemplar der vordefinierten Startzustandsklasse Diese Startzustandklasse isteine der konkreten Zustandsklassen Aumlndert sich der Zustand so wird die Referenz aufein Exemplar der entsprechenden neuen Zustandsklasse umgebogen Dadurch wird deraktuelle Zustand gespeichert In den Listings 3 und 4 waumlre das entsprechend die Variablezustand die zu Beginn ein Exemplar der Klasse LampeZustandLichtAus haumlltIm Zustandsmuster ist nicht vorgegeben wann Objekte erzeugt und zerstoumlrt werden
sollten Hierbei bieten sich zwei Moumlglichkeiten an
bull Eine Moumlglichkeit ist das Erzeugen des Zustandsobjektes bei Bedarf und die Zerstouml-rung bei Zustandsaumlnderung Diese Alternative laumlsst sich den meisten Auspraumlgungendes Zustandsmusters einfach realisieren
bull Dann gibt es noch die Option in der Kontextklasse ein Exemplar jeder Zustands-klasse zu erzeugen und die Referenzen zB in Exemplarvariablen zu speichern Nunfinden bei Zustandsuumlbergaumlngen Zuweisungen zur entsprechenden Variable stattBei dieser Moumlglichkeit werden die Objekte nie bzw erst am Ende der Ausfuumlhrungdes Programms zerstoumlrt
Die erste Alternative sollte man bevorzugen wenn noch nicht klar ist welche Zustaumlndezur Laufzeit benoumltigt werden und die Frequenz der Zustandsuumlbergaumlnge nicht sehr hochist Wechseln die Zustaumlnde jedoch haumlufig so sollte man eher die zweite Option umsetzenKoumlnnen mehrere Kontexte die gleichen Zustandsobjekte verwenden kann Speicher-
platz eingespart werden Solange die Zustandsklassen selbst keinen veraumlnderbaren Zu-stand besitzen ist das theoretisch moumlglich Es bringt jedoch auch die Gefahr mit sichdass eine unnoumltig enge Kopplung zwischen zwei verschiedenen Kontexten entstehtNun gibt das Zustandsmuster allerdings nicht vor welche Klasse oder Klassen die
Transitionsverwaltung zu uumlbernehmen haben Deshalb gibt es mehrere Moumlglichkeitenwelche Klassen die Transitionslogik beinhalten koumlnnen Welche der beiden Moumlglichkeiten
8
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
Programmiersprachen oder gar unter anderen Programmierparadigmen als denen derObjektorientierung lassen wir auszligen vorWeil einige der beruumlhrten Themen fortgeschrittener Natur sind setzen wir fuumlr das
tiefgehende Verstaumlndnis dieses Papers zumindest solide Grundlagen in den folgendenBereichen voraus
bull Prinzipien der objektorientierten Modellierung
bull Grundidee und Zweck objektorientierter Entwurfsmuster
bull Umgang mit den Sprachmitteln von Java
Die Kenntnis gaumlngiger Zustandsautomaten-Modelle wie des endlichen Automaten kannweiterhin hilfreich sein
2 Ein einfaches zustandsbasiertes SystemIn der Praxis werden zustandsbasierte Systeme oft sehr komplex Mit steigenden Anfor-derungen muumlssen dann neue Zustaumlnde eingebaut und neues Verhalten entwickelt werdenDies bringt die Notwendigkeit mit sich saubere und flexible Methoden der Umsetzungdes Zustandsverhaltens zu beherrschenDennoch werden wir die verschiedenen Methoden in diesem Paper an einem einfachen
und uumlberschaubaren System demonstrieren Auch wenn damit die Vorteile der verschie-denen Methoden nicht so sehr ins Auge fallen sind wir der Meinung dass ein kleinesBeispiel der Verstaumlndlichkeit mehr nuumltzt als ein riesiges System mit einer groszligen Mengevon ZustaumlndenDie folgende Spezifikation beschreibt das Beispiel welches wir fuumlr dieses Paper ausge-
waumlhlt haben
Eine Lampe mit Kippschalter habe drei Zustaumlnde bdquoVolle Helligkeitldquo bdquoHalbeHelligkeitldquo und bdquoLicht ausldquo Es gibt zwei moumlgliche Aktionen fuumlr Klienten desSystems bdquoKippschalter links druumlckenldquo und bdquoKippschalter rechts druumlckenldquo (imFolgenden bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquo)Befindet sich der Kippschalter in der Mittelstellung so hat die Lampe den
Zustand bdquoLicht ausldquo Die Aktion bdquodruumlcke linksldquo fuumlhrt dann zu einem Zustands-wechsel nach bdquoVolle Helligkeitldquo bdquodruumlcke rechtsldquo analog nach bdquoHalbe HelligkeitldquoIm Zustand bdquoVolle Helligkeitldquo bewirkt die Aktion bdquodruumlcke linksldquo nichts
bdquodruumlcke rechtsldquo fuumlhrt zu einem Zustandswechsel nach bdquoLicht ausldquo Analoges giltfuumlr den Zustand bdquoHalbe Helligkeitldquo bdquodruumlcke rechtsldquo fuumlhrt zu keinem Zustands-uumlbergang und bdquodruumlcke linksldquo zu einem Zustandswechsel nach bdquoLicht ausldquoDie aktuelle Helligkeit der Lampe kann als Zahl zwischen 00 und 10 abgefragt
werden Im Zustand bdquoLicht ausldquo liegt sie bei 00 im Zustand bdquoHalbe Helligkeitldquobei 05 und im Zustand bdquoVolle Helligkeitldquo bei 10Bei Inbetriebnahme des Systems ist bdquoLicht ausldquo der Startzustand
4
Abbildung 1 Schematische Darstellung des Kippschalters im Zustand bdquoHalbe Helligkeitldquo
Licht aus
druumlcke rechts
druuml
cke
links
druuml
cke rech
ts
HalbeHelligkeit
VolleHelligkeit
druumlcke rechts
druumlcke links druumlcke links
Abbildung 2 Zustandsdiagramm des Lichtschalters
Der genannte Kippschalter ist ein gaumlngiger 3-Positionen-Kippschalter mit entsprechen-den Markierungen (Abbildung 1)Diese Spezifikation laumlsst sich nicht nur in Textform sondern auch zB als aumlquivalentes
Zustandsdiagramm ausdruumlcken (Abbildung 2)In den nun folgenden Abschnitten wollen wir einige Moumlglichkeiten erlaumlutern diese
Spezifikation in Java zu modellieren Dabei werden wir die verschiedenen Ansaumltze aufKriterien wie Fehleranfaumllligkeit und Erweiterbarkeit untersuchen
3 Loumlsungsansatz 1 Die naive UmsetzungDieser erste Ansatz entspricht der intuitiven Herangehensweise Es ist die Loumlsung dienormalerweise entsteht wenn keine bewusste Entscheidung fuumlr eine bestimmte Umset-zung von zustandsbasiertem Verhalten gefallen ist
31 EntwurfHierbei wird der aktuelle Zustand der Lampe in einem einfachen Zustandsfeld gehaltenIm verbreitetsten Fall waumlhlt die implementierende Person dafuumlr den Typ int mit
der Begruumlndung dass boolean nur zwei moumlgliche Werte hat wogegen im vorliegendenFall drei gebraucht werden Die aktuelle Helligkeit der Lampe wird dann bei Bedarfermittelt indem jedem Zustand eine Helligkeit zugewiesen wird Dazu dient haumlufig einswitch-Konstrukt Eine solche Modellierung kann programmiert etwa dem Code vonListing 1 entsprechen
5
Etwas sauberer und weniger fehleranfaumlllig laumlsst der Code sich gestalten indem statteines Zustandsfelds vom Typ int ein privater innerer Aufzaumlhlungstyp verwendet wirdDiese Verbesserung loumlst einige der Probleme des Entwurfs jedoch bei weitem nicht alleDieser Ansatz ist in Listing 2 umgesetzt
32 EigenschaftenDieser Entwurf entspricht der verbreiteten intuitiven Herangehensweise und ist deshalbin den meisten Faumlllen auch ohne Kenntnis irgendwelcher Entwurfsmuster sofort ver-staumlndlichNegativ faumlllt auf dass die Spezifikation der Zustaumlnde von der des zustandsabhaumlngigen
Verhaltens vergleichsweise weit entfernt ist Wuumlrde weiteres zustandsabhaumlngiges Verhal-ten neben der gibHelligkeit-Methode noumltig werden so muumlssten an mehreren Stellen inder Klasse alle Zustaumlnde und ihr jeweiliges spezifisches Verhalten aufgezaumlhlt werdenDas ist ein deutliches Zeichen fuumlr niedrige Kohaumlsion und laumluft anerkannten Designprin-
zipien zuwider Durch die immer wieder noumltige Aufzaumlhlung der Zustaumlnde wird die War-tung bei veraumlnderten Anforderungen stark erschwertBei der Variante mit einer int-Variable kommt eine gesteigerte Fehleranfaumllligkeit hin-
zu Durch Programmierfehler kann das Zustandsfeld einen unguumlltigen Wert annehmenwas undefinierte Konsequenzen haben kann Um das zu verhindern muss an allen Stel-len an denen der Zustand abgefragt wird auf eventuelle fehlerhafte Werte reagiert wer-den (in unserem Beispiel in Listing 1 wurde darauf geachtet) Wird ein Aufzaumlhlungstypverwendet wird diese komplette Fehlerklasse ausgeschlossen
Zusammenfassung
+ intuitiv schnell erfassbar
minus niedrige Kohaumlsion
minus erschwerte Wart- und Erweiterbarkeit
minus (ohne Aufzaumlhlungstyp gesteigerte Anfaumllligkeit fuumlr Programmierfehler)
4 Loumlsungsansatz 2 Das ZustandsmusterBei Gamma et al findet sich ein alternativer Vorschlag fuumlr die Implementation von zu-standsbasierten Systemen (vgl [GHJV95]) Das Entwurfsmuster bdquoZustandldquo versucht mitobjektorientierten Mitteln die Zustaumlnde und ihr jeweiliges Verhalten besser zu kapselnund so die Kohaumlsion zu steigern und die Erweiterung zu erleichternDie abstrakte Beschreibung des Musters ist sehr allgemein gehalten und macht kei-
nen Gebrauch von Java-spezifischen Sprachfeatures Wir empfehlen zum Selbststudiumdie Aufbereitung des Themas durch Freeman et al welche das Muster anhand eineskonkreten Beispiels mit Java-Code erklaumlrt (vgl [FFBS04])
6
Context
State myState
request()
myStatehandle()
ltltabstractgtgt
State
handle()
ConcreteStateA
handle()
ConcreteStateB
handle()
Abbildung 3 Klassendiagramm des Zustandsmusters nach Gamma et al
41 Beschreibung des MustersDas Zustandsmuster (engl state pattern) auch bekannt als bdquoObjekte fuumlr Zustaumlndeldquo(engl objects for states) gehoumlrt zur Kategorie der Verhaltensmuster (engl behavioralpatterns) und ist eines der Muster der bdquoGang of Fourldquo Der Sinn des Zustandsmusters istes die Veraumlnderung des Zustandes eines Objekts durch die scheinbare Aumlnderung seinerKlasse darzustellen indem Teile des Codes der von dem Objekt ausgefuumlhrt wird zurLaufzeit austauschbar gemacht werdenMan kann dieses Entwurfsmuster prinzipiell uumlberall dort anwenden wo das Verhalten
eines Objekts sich abhaumlngig von seinem Zustand zur Laufzeit aumlndert Der Einsatz lohntsich insbesondere dann wenn in einer Klasse an vielen Stellen im Code die gleicheZustandsunterscheidung mittels if- oder switch-Konstrukten erfolgtDas Zustandsmuster besteht aus drei Teilen (vgl Abbildung 3)
1 Den Rahmen bildet eine Kontextklasse welche nach auszligen hin den fachlichen Ge-genstand modelliert und intern ein Exemplar einer Zustandsklasse haumllt
2 Weiterhin gibt es ein Interface oder eine abstrakte Klasse die vorgibt welche Ope-rationen von jedem konkreten Zustand implementiert werden muumlssen Des Weite-ren ermoumlglicht der dadurch definierte Typ es dem Kontext durch polymorpheZuweisungen zwischen den konkreten Zustaumlnden zu wechseln
3 Auszligerdem muumlssen mindestens eine (sinnvollerweise mehrere) konkrete Zustands-klassen existieren von denen jede fuumlr sich einen Zustand mit seinem Verhaltenimplementiert Dieser Zustand ist zumeist durch eine Anzahl von zustandsspe-zifischen Konstanten undoder einprogrammierte je nach Zustand verschiedeneAlgorithmen verkoumlrpert
7
42 EntwurfNimmt man das vorangegangene Beispiel des Kippschalters so kann man an der naivenUmsetzung erkennen dass durch die vielen notwendigen if-Abfragen (in anderen Bei-spielen auch switchcase-Konstrukte) der Quelltext langsam unuumlbersichtlich und kom-pliziert wird Um solche Abfragen zu vermeiden wird in diesem Muster jeder Zustanddurch eine eigene Klasse abgebildetBei unserem Beispiel sind das drei Zustandsklassen bdquoVolle Helligkeitldquo bdquoHalbe Hellig-
keitldquo und bdquoLicht ausldquo Nun sind diese Zustandsklassen prinzipbedingt nicht voumlllig un-terschiedlich Ihre Operationen bilden eine einheitliche Schnittstelle Deshalb definiertman ein Interface oder eine abstrakte Klasse welche die gemeinsamen Operationen derkonkreten Zustandsklassen vorgibtIn unseren Quelltextbeispielen (Listings 3 und 4) waumlre dies das Interface LampeZustand
Unsere konkreten Zustandsklassen sind entsprechend LampeZustandHalbeHelligkeit so-wie LampeZustandVolleHelligkeit und LampeZustandLichtAus Bei der Klasse Lampe
handelt es sich um eine sogenannte Kontextklasse welche die Zustandsklassen verwen-det Als Startzustand haumllt die Kontextklasse in einer Exemplarvariablen die Referenzauf ein Exemplar der vordefinierten Startzustandsklasse Diese Startzustandklasse isteine der konkreten Zustandsklassen Aumlndert sich der Zustand so wird die Referenz aufein Exemplar der entsprechenden neuen Zustandsklasse umgebogen Dadurch wird deraktuelle Zustand gespeichert In den Listings 3 und 4 waumlre das entsprechend die Variablezustand die zu Beginn ein Exemplar der Klasse LampeZustandLichtAus haumlltIm Zustandsmuster ist nicht vorgegeben wann Objekte erzeugt und zerstoumlrt werden
sollten Hierbei bieten sich zwei Moumlglichkeiten an
bull Eine Moumlglichkeit ist das Erzeugen des Zustandsobjektes bei Bedarf und die Zerstouml-rung bei Zustandsaumlnderung Diese Alternative laumlsst sich den meisten Auspraumlgungendes Zustandsmusters einfach realisieren
bull Dann gibt es noch die Option in der Kontextklasse ein Exemplar jeder Zustands-klasse zu erzeugen und die Referenzen zB in Exemplarvariablen zu speichern Nunfinden bei Zustandsuumlbergaumlngen Zuweisungen zur entsprechenden Variable stattBei dieser Moumlglichkeit werden die Objekte nie bzw erst am Ende der Ausfuumlhrungdes Programms zerstoumlrt
Die erste Alternative sollte man bevorzugen wenn noch nicht klar ist welche Zustaumlndezur Laufzeit benoumltigt werden und die Frequenz der Zustandsuumlbergaumlnge nicht sehr hochist Wechseln die Zustaumlnde jedoch haumlufig so sollte man eher die zweite Option umsetzenKoumlnnen mehrere Kontexte die gleichen Zustandsobjekte verwenden kann Speicher-
platz eingespart werden Solange die Zustandsklassen selbst keinen veraumlnderbaren Zu-stand besitzen ist das theoretisch moumlglich Es bringt jedoch auch die Gefahr mit sichdass eine unnoumltig enge Kopplung zwischen zwei verschiedenen Kontexten entstehtNun gibt das Zustandsmuster allerdings nicht vor welche Klasse oder Klassen die
Transitionsverwaltung zu uumlbernehmen haben Deshalb gibt es mehrere Moumlglichkeitenwelche Klassen die Transitionslogik beinhalten koumlnnen Welche der beiden Moumlglichkeiten
8
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
Abbildung 1 Schematische Darstellung des Kippschalters im Zustand bdquoHalbe Helligkeitldquo
Licht aus
druumlcke rechts
druuml
cke
links
druuml
cke rech
ts
HalbeHelligkeit
VolleHelligkeit
druumlcke rechts
druumlcke links druumlcke links
Abbildung 2 Zustandsdiagramm des Lichtschalters
Der genannte Kippschalter ist ein gaumlngiger 3-Positionen-Kippschalter mit entsprechen-den Markierungen (Abbildung 1)Diese Spezifikation laumlsst sich nicht nur in Textform sondern auch zB als aumlquivalentes
Zustandsdiagramm ausdruumlcken (Abbildung 2)In den nun folgenden Abschnitten wollen wir einige Moumlglichkeiten erlaumlutern diese
Spezifikation in Java zu modellieren Dabei werden wir die verschiedenen Ansaumltze aufKriterien wie Fehleranfaumllligkeit und Erweiterbarkeit untersuchen
3 Loumlsungsansatz 1 Die naive UmsetzungDieser erste Ansatz entspricht der intuitiven Herangehensweise Es ist die Loumlsung dienormalerweise entsteht wenn keine bewusste Entscheidung fuumlr eine bestimmte Umset-zung von zustandsbasiertem Verhalten gefallen ist
31 EntwurfHierbei wird der aktuelle Zustand der Lampe in einem einfachen Zustandsfeld gehaltenIm verbreitetsten Fall waumlhlt die implementierende Person dafuumlr den Typ int mit
der Begruumlndung dass boolean nur zwei moumlgliche Werte hat wogegen im vorliegendenFall drei gebraucht werden Die aktuelle Helligkeit der Lampe wird dann bei Bedarfermittelt indem jedem Zustand eine Helligkeit zugewiesen wird Dazu dient haumlufig einswitch-Konstrukt Eine solche Modellierung kann programmiert etwa dem Code vonListing 1 entsprechen
5
Etwas sauberer und weniger fehleranfaumlllig laumlsst der Code sich gestalten indem statteines Zustandsfelds vom Typ int ein privater innerer Aufzaumlhlungstyp verwendet wirdDiese Verbesserung loumlst einige der Probleme des Entwurfs jedoch bei weitem nicht alleDieser Ansatz ist in Listing 2 umgesetzt
32 EigenschaftenDieser Entwurf entspricht der verbreiteten intuitiven Herangehensweise und ist deshalbin den meisten Faumlllen auch ohne Kenntnis irgendwelcher Entwurfsmuster sofort ver-staumlndlichNegativ faumlllt auf dass die Spezifikation der Zustaumlnde von der des zustandsabhaumlngigen
Verhaltens vergleichsweise weit entfernt ist Wuumlrde weiteres zustandsabhaumlngiges Verhal-ten neben der gibHelligkeit-Methode noumltig werden so muumlssten an mehreren Stellen inder Klasse alle Zustaumlnde und ihr jeweiliges spezifisches Verhalten aufgezaumlhlt werdenDas ist ein deutliches Zeichen fuumlr niedrige Kohaumlsion und laumluft anerkannten Designprin-
zipien zuwider Durch die immer wieder noumltige Aufzaumlhlung der Zustaumlnde wird die War-tung bei veraumlnderten Anforderungen stark erschwertBei der Variante mit einer int-Variable kommt eine gesteigerte Fehleranfaumllligkeit hin-
zu Durch Programmierfehler kann das Zustandsfeld einen unguumlltigen Wert annehmenwas undefinierte Konsequenzen haben kann Um das zu verhindern muss an allen Stel-len an denen der Zustand abgefragt wird auf eventuelle fehlerhafte Werte reagiert wer-den (in unserem Beispiel in Listing 1 wurde darauf geachtet) Wird ein Aufzaumlhlungstypverwendet wird diese komplette Fehlerklasse ausgeschlossen
Zusammenfassung
+ intuitiv schnell erfassbar
minus niedrige Kohaumlsion
minus erschwerte Wart- und Erweiterbarkeit
minus (ohne Aufzaumlhlungstyp gesteigerte Anfaumllligkeit fuumlr Programmierfehler)
4 Loumlsungsansatz 2 Das ZustandsmusterBei Gamma et al findet sich ein alternativer Vorschlag fuumlr die Implementation von zu-standsbasierten Systemen (vgl [GHJV95]) Das Entwurfsmuster bdquoZustandldquo versucht mitobjektorientierten Mitteln die Zustaumlnde und ihr jeweiliges Verhalten besser zu kapselnund so die Kohaumlsion zu steigern und die Erweiterung zu erleichternDie abstrakte Beschreibung des Musters ist sehr allgemein gehalten und macht kei-
nen Gebrauch von Java-spezifischen Sprachfeatures Wir empfehlen zum Selbststudiumdie Aufbereitung des Themas durch Freeman et al welche das Muster anhand eineskonkreten Beispiels mit Java-Code erklaumlrt (vgl [FFBS04])
6
Context
State myState
request()
myStatehandle()
ltltabstractgtgt
State
handle()
ConcreteStateA
handle()
ConcreteStateB
handle()
Abbildung 3 Klassendiagramm des Zustandsmusters nach Gamma et al
41 Beschreibung des MustersDas Zustandsmuster (engl state pattern) auch bekannt als bdquoObjekte fuumlr Zustaumlndeldquo(engl objects for states) gehoumlrt zur Kategorie der Verhaltensmuster (engl behavioralpatterns) und ist eines der Muster der bdquoGang of Fourldquo Der Sinn des Zustandsmusters istes die Veraumlnderung des Zustandes eines Objekts durch die scheinbare Aumlnderung seinerKlasse darzustellen indem Teile des Codes der von dem Objekt ausgefuumlhrt wird zurLaufzeit austauschbar gemacht werdenMan kann dieses Entwurfsmuster prinzipiell uumlberall dort anwenden wo das Verhalten
eines Objekts sich abhaumlngig von seinem Zustand zur Laufzeit aumlndert Der Einsatz lohntsich insbesondere dann wenn in einer Klasse an vielen Stellen im Code die gleicheZustandsunterscheidung mittels if- oder switch-Konstrukten erfolgtDas Zustandsmuster besteht aus drei Teilen (vgl Abbildung 3)
1 Den Rahmen bildet eine Kontextklasse welche nach auszligen hin den fachlichen Ge-genstand modelliert und intern ein Exemplar einer Zustandsklasse haumllt
2 Weiterhin gibt es ein Interface oder eine abstrakte Klasse die vorgibt welche Ope-rationen von jedem konkreten Zustand implementiert werden muumlssen Des Weite-ren ermoumlglicht der dadurch definierte Typ es dem Kontext durch polymorpheZuweisungen zwischen den konkreten Zustaumlnden zu wechseln
3 Auszligerdem muumlssen mindestens eine (sinnvollerweise mehrere) konkrete Zustands-klassen existieren von denen jede fuumlr sich einen Zustand mit seinem Verhaltenimplementiert Dieser Zustand ist zumeist durch eine Anzahl von zustandsspe-zifischen Konstanten undoder einprogrammierte je nach Zustand verschiedeneAlgorithmen verkoumlrpert
7
42 EntwurfNimmt man das vorangegangene Beispiel des Kippschalters so kann man an der naivenUmsetzung erkennen dass durch die vielen notwendigen if-Abfragen (in anderen Bei-spielen auch switchcase-Konstrukte) der Quelltext langsam unuumlbersichtlich und kom-pliziert wird Um solche Abfragen zu vermeiden wird in diesem Muster jeder Zustanddurch eine eigene Klasse abgebildetBei unserem Beispiel sind das drei Zustandsklassen bdquoVolle Helligkeitldquo bdquoHalbe Hellig-
keitldquo und bdquoLicht ausldquo Nun sind diese Zustandsklassen prinzipbedingt nicht voumlllig un-terschiedlich Ihre Operationen bilden eine einheitliche Schnittstelle Deshalb definiertman ein Interface oder eine abstrakte Klasse welche die gemeinsamen Operationen derkonkreten Zustandsklassen vorgibtIn unseren Quelltextbeispielen (Listings 3 und 4) waumlre dies das Interface LampeZustand
Unsere konkreten Zustandsklassen sind entsprechend LampeZustandHalbeHelligkeit so-wie LampeZustandVolleHelligkeit und LampeZustandLichtAus Bei der Klasse Lampe
handelt es sich um eine sogenannte Kontextklasse welche die Zustandsklassen verwen-det Als Startzustand haumllt die Kontextklasse in einer Exemplarvariablen die Referenzauf ein Exemplar der vordefinierten Startzustandsklasse Diese Startzustandklasse isteine der konkreten Zustandsklassen Aumlndert sich der Zustand so wird die Referenz aufein Exemplar der entsprechenden neuen Zustandsklasse umgebogen Dadurch wird deraktuelle Zustand gespeichert In den Listings 3 und 4 waumlre das entsprechend die Variablezustand die zu Beginn ein Exemplar der Klasse LampeZustandLichtAus haumlltIm Zustandsmuster ist nicht vorgegeben wann Objekte erzeugt und zerstoumlrt werden
sollten Hierbei bieten sich zwei Moumlglichkeiten an
bull Eine Moumlglichkeit ist das Erzeugen des Zustandsobjektes bei Bedarf und die Zerstouml-rung bei Zustandsaumlnderung Diese Alternative laumlsst sich den meisten Auspraumlgungendes Zustandsmusters einfach realisieren
bull Dann gibt es noch die Option in der Kontextklasse ein Exemplar jeder Zustands-klasse zu erzeugen und die Referenzen zB in Exemplarvariablen zu speichern Nunfinden bei Zustandsuumlbergaumlngen Zuweisungen zur entsprechenden Variable stattBei dieser Moumlglichkeit werden die Objekte nie bzw erst am Ende der Ausfuumlhrungdes Programms zerstoumlrt
Die erste Alternative sollte man bevorzugen wenn noch nicht klar ist welche Zustaumlndezur Laufzeit benoumltigt werden und die Frequenz der Zustandsuumlbergaumlnge nicht sehr hochist Wechseln die Zustaumlnde jedoch haumlufig so sollte man eher die zweite Option umsetzenKoumlnnen mehrere Kontexte die gleichen Zustandsobjekte verwenden kann Speicher-
platz eingespart werden Solange die Zustandsklassen selbst keinen veraumlnderbaren Zu-stand besitzen ist das theoretisch moumlglich Es bringt jedoch auch die Gefahr mit sichdass eine unnoumltig enge Kopplung zwischen zwei verschiedenen Kontexten entstehtNun gibt das Zustandsmuster allerdings nicht vor welche Klasse oder Klassen die
Transitionsverwaltung zu uumlbernehmen haben Deshalb gibt es mehrere Moumlglichkeitenwelche Klassen die Transitionslogik beinhalten koumlnnen Welche der beiden Moumlglichkeiten
8
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
Etwas sauberer und weniger fehleranfaumlllig laumlsst der Code sich gestalten indem statteines Zustandsfelds vom Typ int ein privater innerer Aufzaumlhlungstyp verwendet wirdDiese Verbesserung loumlst einige der Probleme des Entwurfs jedoch bei weitem nicht alleDieser Ansatz ist in Listing 2 umgesetzt
32 EigenschaftenDieser Entwurf entspricht der verbreiteten intuitiven Herangehensweise und ist deshalbin den meisten Faumlllen auch ohne Kenntnis irgendwelcher Entwurfsmuster sofort ver-staumlndlichNegativ faumlllt auf dass die Spezifikation der Zustaumlnde von der des zustandsabhaumlngigen
Verhaltens vergleichsweise weit entfernt ist Wuumlrde weiteres zustandsabhaumlngiges Verhal-ten neben der gibHelligkeit-Methode noumltig werden so muumlssten an mehreren Stellen inder Klasse alle Zustaumlnde und ihr jeweiliges spezifisches Verhalten aufgezaumlhlt werdenDas ist ein deutliches Zeichen fuumlr niedrige Kohaumlsion und laumluft anerkannten Designprin-
zipien zuwider Durch die immer wieder noumltige Aufzaumlhlung der Zustaumlnde wird die War-tung bei veraumlnderten Anforderungen stark erschwertBei der Variante mit einer int-Variable kommt eine gesteigerte Fehleranfaumllligkeit hin-
zu Durch Programmierfehler kann das Zustandsfeld einen unguumlltigen Wert annehmenwas undefinierte Konsequenzen haben kann Um das zu verhindern muss an allen Stel-len an denen der Zustand abgefragt wird auf eventuelle fehlerhafte Werte reagiert wer-den (in unserem Beispiel in Listing 1 wurde darauf geachtet) Wird ein Aufzaumlhlungstypverwendet wird diese komplette Fehlerklasse ausgeschlossen
Zusammenfassung
+ intuitiv schnell erfassbar
minus niedrige Kohaumlsion
minus erschwerte Wart- und Erweiterbarkeit
minus (ohne Aufzaumlhlungstyp gesteigerte Anfaumllligkeit fuumlr Programmierfehler)
4 Loumlsungsansatz 2 Das ZustandsmusterBei Gamma et al findet sich ein alternativer Vorschlag fuumlr die Implementation von zu-standsbasierten Systemen (vgl [GHJV95]) Das Entwurfsmuster bdquoZustandldquo versucht mitobjektorientierten Mitteln die Zustaumlnde und ihr jeweiliges Verhalten besser zu kapselnund so die Kohaumlsion zu steigern und die Erweiterung zu erleichternDie abstrakte Beschreibung des Musters ist sehr allgemein gehalten und macht kei-
nen Gebrauch von Java-spezifischen Sprachfeatures Wir empfehlen zum Selbststudiumdie Aufbereitung des Themas durch Freeman et al welche das Muster anhand eineskonkreten Beispiels mit Java-Code erklaumlrt (vgl [FFBS04])
6
Context
State myState
request()
myStatehandle()
ltltabstractgtgt
State
handle()
ConcreteStateA
handle()
ConcreteStateB
handle()
Abbildung 3 Klassendiagramm des Zustandsmusters nach Gamma et al
41 Beschreibung des MustersDas Zustandsmuster (engl state pattern) auch bekannt als bdquoObjekte fuumlr Zustaumlndeldquo(engl objects for states) gehoumlrt zur Kategorie der Verhaltensmuster (engl behavioralpatterns) und ist eines der Muster der bdquoGang of Fourldquo Der Sinn des Zustandsmusters istes die Veraumlnderung des Zustandes eines Objekts durch die scheinbare Aumlnderung seinerKlasse darzustellen indem Teile des Codes der von dem Objekt ausgefuumlhrt wird zurLaufzeit austauschbar gemacht werdenMan kann dieses Entwurfsmuster prinzipiell uumlberall dort anwenden wo das Verhalten
eines Objekts sich abhaumlngig von seinem Zustand zur Laufzeit aumlndert Der Einsatz lohntsich insbesondere dann wenn in einer Klasse an vielen Stellen im Code die gleicheZustandsunterscheidung mittels if- oder switch-Konstrukten erfolgtDas Zustandsmuster besteht aus drei Teilen (vgl Abbildung 3)
1 Den Rahmen bildet eine Kontextklasse welche nach auszligen hin den fachlichen Ge-genstand modelliert und intern ein Exemplar einer Zustandsklasse haumllt
2 Weiterhin gibt es ein Interface oder eine abstrakte Klasse die vorgibt welche Ope-rationen von jedem konkreten Zustand implementiert werden muumlssen Des Weite-ren ermoumlglicht der dadurch definierte Typ es dem Kontext durch polymorpheZuweisungen zwischen den konkreten Zustaumlnden zu wechseln
3 Auszligerdem muumlssen mindestens eine (sinnvollerweise mehrere) konkrete Zustands-klassen existieren von denen jede fuumlr sich einen Zustand mit seinem Verhaltenimplementiert Dieser Zustand ist zumeist durch eine Anzahl von zustandsspe-zifischen Konstanten undoder einprogrammierte je nach Zustand verschiedeneAlgorithmen verkoumlrpert
7
42 EntwurfNimmt man das vorangegangene Beispiel des Kippschalters so kann man an der naivenUmsetzung erkennen dass durch die vielen notwendigen if-Abfragen (in anderen Bei-spielen auch switchcase-Konstrukte) der Quelltext langsam unuumlbersichtlich und kom-pliziert wird Um solche Abfragen zu vermeiden wird in diesem Muster jeder Zustanddurch eine eigene Klasse abgebildetBei unserem Beispiel sind das drei Zustandsklassen bdquoVolle Helligkeitldquo bdquoHalbe Hellig-
keitldquo und bdquoLicht ausldquo Nun sind diese Zustandsklassen prinzipbedingt nicht voumlllig un-terschiedlich Ihre Operationen bilden eine einheitliche Schnittstelle Deshalb definiertman ein Interface oder eine abstrakte Klasse welche die gemeinsamen Operationen derkonkreten Zustandsklassen vorgibtIn unseren Quelltextbeispielen (Listings 3 und 4) waumlre dies das Interface LampeZustand
Unsere konkreten Zustandsklassen sind entsprechend LampeZustandHalbeHelligkeit so-wie LampeZustandVolleHelligkeit und LampeZustandLichtAus Bei der Klasse Lampe
handelt es sich um eine sogenannte Kontextklasse welche die Zustandsklassen verwen-det Als Startzustand haumllt die Kontextklasse in einer Exemplarvariablen die Referenzauf ein Exemplar der vordefinierten Startzustandsklasse Diese Startzustandklasse isteine der konkreten Zustandsklassen Aumlndert sich der Zustand so wird die Referenz aufein Exemplar der entsprechenden neuen Zustandsklasse umgebogen Dadurch wird deraktuelle Zustand gespeichert In den Listings 3 und 4 waumlre das entsprechend die Variablezustand die zu Beginn ein Exemplar der Klasse LampeZustandLichtAus haumlltIm Zustandsmuster ist nicht vorgegeben wann Objekte erzeugt und zerstoumlrt werden
sollten Hierbei bieten sich zwei Moumlglichkeiten an
bull Eine Moumlglichkeit ist das Erzeugen des Zustandsobjektes bei Bedarf und die Zerstouml-rung bei Zustandsaumlnderung Diese Alternative laumlsst sich den meisten Auspraumlgungendes Zustandsmusters einfach realisieren
bull Dann gibt es noch die Option in der Kontextklasse ein Exemplar jeder Zustands-klasse zu erzeugen und die Referenzen zB in Exemplarvariablen zu speichern Nunfinden bei Zustandsuumlbergaumlngen Zuweisungen zur entsprechenden Variable stattBei dieser Moumlglichkeit werden die Objekte nie bzw erst am Ende der Ausfuumlhrungdes Programms zerstoumlrt
Die erste Alternative sollte man bevorzugen wenn noch nicht klar ist welche Zustaumlndezur Laufzeit benoumltigt werden und die Frequenz der Zustandsuumlbergaumlnge nicht sehr hochist Wechseln die Zustaumlnde jedoch haumlufig so sollte man eher die zweite Option umsetzenKoumlnnen mehrere Kontexte die gleichen Zustandsobjekte verwenden kann Speicher-
platz eingespart werden Solange die Zustandsklassen selbst keinen veraumlnderbaren Zu-stand besitzen ist das theoretisch moumlglich Es bringt jedoch auch die Gefahr mit sichdass eine unnoumltig enge Kopplung zwischen zwei verschiedenen Kontexten entstehtNun gibt das Zustandsmuster allerdings nicht vor welche Klasse oder Klassen die
Transitionsverwaltung zu uumlbernehmen haben Deshalb gibt es mehrere Moumlglichkeitenwelche Klassen die Transitionslogik beinhalten koumlnnen Welche der beiden Moumlglichkeiten
8
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
Context
State myState
request()
myStatehandle()
ltltabstractgtgt
State
handle()
ConcreteStateA
handle()
ConcreteStateB
handle()
Abbildung 3 Klassendiagramm des Zustandsmusters nach Gamma et al
41 Beschreibung des MustersDas Zustandsmuster (engl state pattern) auch bekannt als bdquoObjekte fuumlr Zustaumlndeldquo(engl objects for states) gehoumlrt zur Kategorie der Verhaltensmuster (engl behavioralpatterns) und ist eines der Muster der bdquoGang of Fourldquo Der Sinn des Zustandsmusters istes die Veraumlnderung des Zustandes eines Objekts durch die scheinbare Aumlnderung seinerKlasse darzustellen indem Teile des Codes der von dem Objekt ausgefuumlhrt wird zurLaufzeit austauschbar gemacht werdenMan kann dieses Entwurfsmuster prinzipiell uumlberall dort anwenden wo das Verhalten
eines Objekts sich abhaumlngig von seinem Zustand zur Laufzeit aumlndert Der Einsatz lohntsich insbesondere dann wenn in einer Klasse an vielen Stellen im Code die gleicheZustandsunterscheidung mittels if- oder switch-Konstrukten erfolgtDas Zustandsmuster besteht aus drei Teilen (vgl Abbildung 3)
1 Den Rahmen bildet eine Kontextklasse welche nach auszligen hin den fachlichen Ge-genstand modelliert und intern ein Exemplar einer Zustandsklasse haumllt
2 Weiterhin gibt es ein Interface oder eine abstrakte Klasse die vorgibt welche Ope-rationen von jedem konkreten Zustand implementiert werden muumlssen Des Weite-ren ermoumlglicht der dadurch definierte Typ es dem Kontext durch polymorpheZuweisungen zwischen den konkreten Zustaumlnden zu wechseln
3 Auszligerdem muumlssen mindestens eine (sinnvollerweise mehrere) konkrete Zustands-klassen existieren von denen jede fuumlr sich einen Zustand mit seinem Verhaltenimplementiert Dieser Zustand ist zumeist durch eine Anzahl von zustandsspe-zifischen Konstanten undoder einprogrammierte je nach Zustand verschiedeneAlgorithmen verkoumlrpert
7
42 EntwurfNimmt man das vorangegangene Beispiel des Kippschalters so kann man an der naivenUmsetzung erkennen dass durch die vielen notwendigen if-Abfragen (in anderen Bei-spielen auch switchcase-Konstrukte) der Quelltext langsam unuumlbersichtlich und kom-pliziert wird Um solche Abfragen zu vermeiden wird in diesem Muster jeder Zustanddurch eine eigene Klasse abgebildetBei unserem Beispiel sind das drei Zustandsklassen bdquoVolle Helligkeitldquo bdquoHalbe Hellig-
keitldquo und bdquoLicht ausldquo Nun sind diese Zustandsklassen prinzipbedingt nicht voumlllig un-terschiedlich Ihre Operationen bilden eine einheitliche Schnittstelle Deshalb definiertman ein Interface oder eine abstrakte Klasse welche die gemeinsamen Operationen derkonkreten Zustandsklassen vorgibtIn unseren Quelltextbeispielen (Listings 3 und 4) waumlre dies das Interface LampeZustand
Unsere konkreten Zustandsklassen sind entsprechend LampeZustandHalbeHelligkeit so-wie LampeZustandVolleHelligkeit und LampeZustandLichtAus Bei der Klasse Lampe
handelt es sich um eine sogenannte Kontextklasse welche die Zustandsklassen verwen-det Als Startzustand haumllt die Kontextklasse in einer Exemplarvariablen die Referenzauf ein Exemplar der vordefinierten Startzustandsklasse Diese Startzustandklasse isteine der konkreten Zustandsklassen Aumlndert sich der Zustand so wird die Referenz aufein Exemplar der entsprechenden neuen Zustandsklasse umgebogen Dadurch wird deraktuelle Zustand gespeichert In den Listings 3 und 4 waumlre das entsprechend die Variablezustand die zu Beginn ein Exemplar der Klasse LampeZustandLichtAus haumlltIm Zustandsmuster ist nicht vorgegeben wann Objekte erzeugt und zerstoumlrt werden
sollten Hierbei bieten sich zwei Moumlglichkeiten an
bull Eine Moumlglichkeit ist das Erzeugen des Zustandsobjektes bei Bedarf und die Zerstouml-rung bei Zustandsaumlnderung Diese Alternative laumlsst sich den meisten Auspraumlgungendes Zustandsmusters einfach realisieren
bull Dann gibt es noch die Option in der Kontextklasse ein Exemplar jeder Zustands-klasse zu erzeugen und die Referenzen zB in Exemplarvariablen zu speichern Nunfinden bei Zustandsuumlbergaumlngen Zuweisungen zur entsprechenden Variable stattBei dieser Moumlglichkeit werden die Objekte nie bzw erst am Ende der Ausfuumlhrungdes Programms zerstoumlrt
Die erste Alternative sollte man bevorzugen wenn noch nicht klar ist welche Zustaumlndezur Laufzeit benoumltigt werden und die Frequenz der Zustandsuumlbergaumlnge nicht sehr hochist Wechseln die Zustaumlnde jedoch haumlufig so sollte man eher die zweite Option umsetzenKoumlnnen mehrere Kontexte die gleichen Zustandsobjekte verwenden kann Speicher-
platz eingespart werden Solange die Zustandsklassen selbst keinen veraumlnderbaren Zu-stand besitzen ist das theoretisch moumlglich Es bringt jedoch auch die Gefahr mit sichdass eine unnoumltig enge Kopplung zwischen zwei verschiedenen Kontexten entstehtNun gibt das Zustandsmuster allerdings nicht vor welche Klasse oder Klassen die
Transitionsverwaltung zu uumlbernehmen haben Deshalb gibt es mehrere Moumlglichkeitenwelche Klassen die Transitionslogik beinhalten koumlnnen Welche der beiden Moumlglichkeiten
8
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
42 EntwurfNimmt man das vorangegangene Beispiel des Kippschalters so kann man an der naivenUmsetzung erkennen dass durch die vielen notwendigen if-Abfragen (in anderen Bei-spielen auch switchcase-Konstrukte) der Quelltext langsam unuumlbersichtlich und kom-pliziert wird Um solche Abfragen zu vermeiden wird in diesem Muster jeder Zustanddurch eine eigene Klasse abgebildetBei unserem Beispiel sind das drei Zustandsklassen bdquoVolle Helligkeitldquo bdquoHalbe Hellig-
keitldquo und bdquoLicht ausldquo Nun sind diese Zustandsklassen prinzipbedingt nicht voumlllig un-terschiedlich Ihre Operationen bilden eine einheitliche Schnittstelle Deshalb definiertman ein Interface oder eine abstrakte Klasse welche die gemeinsamen Operationen derkonkreten Zustandsklassen vorgibtIn unseren Quelltextbeispielen (Listings 3 und 4) waumlre dies das Interface LampeZustand
Unsere konkreten Zustandsklassen sind entsprechend LampeZustandHalbeHelligkeit so-wie LampeZustandVolleHelligkeit und LampeZustandLichtAus Bei der Klasse Lampe
handelt es sich um eine sogenannte Kontextklasse welche die Zustandsklassen verwen-det Als Startzustand haumllt die Kontextklasse in einer Exemplarvariablen die Referenzauf ein Exemplar der vordefinierten Startzustandsklasse Diese Startzustandklasse isteine der konkreten Zustandsklassen Aumlndert sich der Zustand so wird die Referenz aufein Exemplar der entsprechenden neuen Zustandsklasse umgebogen Dadurch wird deraktuelle Zustand gespeichert In den Listings 3 und 4 waumlre das entsprechend die Variablezustand die zu Beginn ein Exemplar der Klasse LampeZustandLichtAus haumlltIm Zustandsmuster ist nicht vorgegeben wann Objekte erzeugt und zerstoumlrt werden
sollten Hierbei bieten sich zwei Moumlglichkeiten an
bull Eine Moumlglichkeit ist das Erzeugen des Zustandsobjektes bei Bedarf und die Zerstouml-rung bei Zustandsaumlnderung Diese Alternative laumlsst sich den meisten Auspraumlgungendes Zustandsmusters einfach realisieren
bull Dann gibt es noch die Option in der Kontextklasse ein Exemplar jeder Zustands-klasse zu erzeugen und die Referenzen zB in Exemplarvariablen zu speichern Nunfinden bei Zustandsuumlbergaumlngen Zuweisungen zur entsprechenden Variable stattBei dieser Moumlglichkeit werden die Objekte nie bzw erst am Ende der Ausfuumlhrungdes Programms zerstoumlrt
Die erste Alternative sollte man bevorzugen wenn noch nicht klar ist welche Zustaumlndezur Laufzeit benoumltigt werden und die Frequenz der Zustandsuumlbergaumlnge nicht sehr hochist Wechseln die Zustaumlnde jedoch haumlufig so sollte man eher die zweite Option umsetzenKoumlnnen mehrere Kontexte die gleichen Zustandsobjekte verwenden kann Speicher-
platz eingespart werden Solange die Zustandsklassen selbst keinen veraumlnderbaren Zu-stand besitzen ist das theoretisch moumlglich Es bringt jedoch auch die Gefahr mit sichdass eine unnoumltig enge Kopplung zwischen zwei verschiedenen Kontexten entstehtNun gibt das Zustandsmuster allerdings nicht vor welche Klasse oder Klassen die
Transitionsverwaltung zu uumlbernehmen haben Deshalb gibt es mehrere Moumlglichkeitenwelche Klassen die Transitionslogik beinhalten koumlnnen Welche der beiden Moumlglichkeiten
8
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
der Transitionsverwaltung genutzt werden sollte haumlngt von der Anzahl der Zustaumlnde vonder Auspraumlgung des zustandsabhaumlngigen Verhaltens und nicht zuletzt von den Vorliebendes Programmierers ab
421 Dezentrale Transitionsverwaltung
Hierbei steckt die gesamte Transitionslogik in den konkreten Zustandsklassen Dies be-deutet dass die Kontextklasse Methodenaufrufe die zu einem Zustandswechsel fuumlhrenan die aktive konkrete Zustandsklasse weitergibtIn unserem Beispiel bedeutet das Delegation der Aufrufe der Methoden drueckeLinks
drueckeRechts und gibHelligkeit an die aktive konkrete Zustandsklasse uumlber die Ex-emplarvariable zustand Somit werden solche Methoden auch in dem Zustandsinterfaceoder der abstrakten Klasse Zustand vorgegeben Erst in den konkreten Zustandsklassenwird dann definiert was bei entsprechenden Aufrufen geschehen soll Im konkreten Zu-stand sind Zustandsabfragen nun natuumlrlich unnoumltig geworden und es kann direkt reagiertwerdenDie Methode gibHelligkeit aus unserem Beispiel gibt einen zustandsabhaumlngigen Wert
zuruumlck und speichert somit zustandsrelevante Daten Hingegen sind die beiden anderenMethoden drueckeLinks und drueckeRechts zustandsveraumlndernde Methoden denn siegeben jeweils einen Zustand zuruumlck (sich selbst oder einen anderen) und beinhalten somitdie TransitionslogikDies bedeutet allerdings auch dass jede Zustandsklasse ihre Nachfolgezustaumlnde kennt
und fuumlhrt in vielen Faumlllen zu zyklischen Abhaumlngigkeiten Solange sich die Implementationan den Rahmen des Zustandsmusters haumllt sehen wir jedoch keinen Grund den Entwurfdogmatisch abzulehnen Zyklische Abhaumlngigkeiten werden schlieszliglich nur zum Problemwenn mehrere Klassen gegenseitig Funktionalitaumlt der jeweils anderen Klasse verwendenwas hier nicht der Fall istDiese Loumlsung entspricht der aus Listing 3 und ist in Abbildung 4 in Form eines Klas-
sendiagramms veranschaulicht
422 Zentrale Transitionsverwaltung
Bei dieser Moumlglichkeit steckt die Transitionslogik in der Kontextklasse Hierbei werdenalle zustandsveraumlndernden Methodenaufrufe nicht nach unten delegiert sondern nur daszustandsspezifische Verhalten wie in unserem Beispiel gibHelligkeitDie Zustaumlnde werden hierbei wieder durch if-Konstrukte abgefragt Hier kennen die
konkreten Zustandsklassen einander nicht Das Zustandsinterface in diesem Beispiel gibtnun auch nur noch die Methode gibHelligkeit vor welche auch als einzige in denkonkreten Zustandsklassen implementiert wirdNun mag einem das Zustandsmuster in der Umsetzung dieses Beispiels als uumlbertrie-
bener Arbeitsaufwand vorkommen Gibt es allerdings weiteres zustandsabhaumlngiges Ver-halten zusaumltzlich zu gibHelligkeit so erspart dieses Vorgehen viele AbfragenIn Listing 4 ist diese Variante umgesetzt Abbildung 5 ist das dazugehoumlrige Klassen-
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
Abbildung 5 Klassendiagramm des Entwurfs aus Listing 4
10
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
43 EigenschaftenDas Zustandsmuster lokalisiert zustandsspezifisches Verhalten Durch das Aufteilen inKontext und konkrete Zustandsklassen befindet sich das zustandspezifische Verhaltenimmer in den konkreten ZustandsklassenWird ein neuer Zustand hinzugefuumlgt muumlssen lediglich zwei Dinge beachtet werden Es
muss eine neue konkrete Zustandsklasse angelegt werden die entsprechende Methodenbereitstellt welche das zustandsabhaumlngige Verhalten beinhalten Auszligerdem muss dieTransitionslogik um die neu hinzugekommenen Zustandsuumlbergaumlnge erweitert werdenDies erleichtert die WartbarkeitKomplexe und unuumlbersichtliche Schachtelungen von Bedingungsanweisungen koumlnnen
vermieden werden Zudem spiegelt sich die Struktur des spezifizierenden Zustandsdia-gramms bei dezentraler Transitionsverwaltung im Klassendiagramm wider Zustands-uumlbergaumlnge sind in Form von bdquobenutztldquo-Beziehungen zwischen den konkreten Zustands-klassen im Klassendiagramm zu sehen Bei zentraler Transitionslogik sind die Zustands-uumlbergaumlnge strikt vom zustandsspezifischen Verhalten getrenntEs bleibt zu bedenken dass der Einsatz des Zustandsmusters meist zu einer komple-
xeren Struktur der Software und einer houmlheren Anzahl kleiner Klassen fuumlhrt Ist daszustandsspezifische Verhalten sehr uumlberschaubar lohnt sich der Mehraufwand in derProgrammstruktur ggf nicht In solchen Faumlllen kann eine der Varianten die wir in denfolgenden Abschnitten vorstellen angebrachter sein
Zusammenfassung
+ saubere Entkopplung der Zustaumlnde untereinander und vom Kontext
+ gesteigerte Uumlbersichtlichkeit der beteiligten Klassen
+ einfache Wart- und Erweiterbarkeit
+ langjaumlhrige Bewaumlhrtheit des Musters
minus struktureller Mehraufwand
44 Verwandte MusterEs gibt einige Entwurfsmuster die haumlufig gemeinsam mit (oder anstelle vom) Zustands-muster zum Einsatz kommen Um in der Hinsicht ein wenig Klarheit zu schaffen werdenwir sie an dieser Stelle kurz beschreiben
bull Das Fliegengewichtsmuster (engl flyweight pattern) ist eines der strukturellenMuster (structural patterns) beschrieben durch Gamma et al (vgl [GHJV95])Man setzt das Fliegengewicht ein wenn es eine sehr hohe Zahl von identischenObjekten gibt die durch die konsequente Anwendung dieses Musters durch eineinziges Objekt ersetzt werden koumlnnen Dieses Muster beinhaltet zwar einen rechtgroszligen Verwaltungsaufwand aber es kann Speicherplatz gespart werden Durch die
11
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
gemeinsame Nutzung von Zustandsobjekten durch verschiedene Kontexte kann inKombination mit dem Zustandsmuster der Speicheraufwand reduziert werden
bull Das Einzelstuumlckmuster (engl singleton pattern) ist ein von Gamma et al be-schriebenes erzeugendes Muster (creational pattern) Dieses Muster findet Verwen-dung wenn nur eine begrenzte Anzahl von Exemplaren (in den meisten Faumlllen nurein Exemplar) einer Klasse existieren soll Um die Anzahl zu beschraumlnken wirdmeist eine statische Instanziierungsoperation definiert Kombiniert mit dem Zu-standsmuster kann zB die Anzahl der Exemplare der konkreten Zustandsklassenbeschraumlnkt werden
bull Das Strategiemuster (engl strategy pattern) ist ebenso wie das Zustandsmusterein Verhaltensmuster und aumlhnelt diesem sehr stark Es wird verwendet wenn sichverwandte Klassen nur in Teilen ihres Verhaltens unterscheiden um dieses Ver-halten zu externalisieren und vom Rest der Klassen zu entkoppeln welche dannvereinheitlicht werden koumlnnen Strukturell sind Strategiemuster und Zustandsmus-ter kaum zu unterscheiden die Einsatzzwecke sind jedoch verschieden
5 Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-EnumsAufzaumlhlungstypen (bdquoEnumsldquo) bieten in Java viele weiterfuumlhrende kaum bekannte Moumlg-lichkeiten (vgl [GJSB05]) Die einzelnen Werte eines Aufzaumlhlungstypen sind in Javatatsaumlchlich Exemplare einer ansonsten nicht instanziierbaren Klasse Diese Klasse kannuumlber weiterfuumlhrende Logik verfuumlgen Sogar die einzelnen Werte koumlnnen mit spezifischemVerhalten versehen werdenMit diesen Mitteln laumlsst sich eine dritte Moumlglichkeit etablieren zustandsspezifisches
Verhalten in Java elegant umzusetzen
51 EntwurfAumlhnlich wie bei der Realisierung des Zustandsmusters mit dezentraler Transitionsver-waltung haumllt die Lampe ihren aktuellen Zustand in einem Zustandsfeld In diesem Fallist LampeZustand jedoch kein Interface sondern ein EnumDieser Enum definiert die drei moumlglichen Zustaumlnde Dem Typ LampeZustand werden
drei Operationen zugeordnet die den zwei Aktionen bdquodruumlcke linksldquo und bdquodruumlcke rechtsldquosowie der Abfrage der Helligkeit entsprechen Jedem der drei Werte des Enums werdenspezielle Implementationen dieser Operationen zugeordnet so dass man an ihnen dieNachfolgezustaumlnde sowie die Helligkeit abfragen kannDieser Entwurf entspricht der Implementation in Listing 5
52 EigenschaftenDiese Variante bringt wie das urspruumlngliche Zustandsmuster eine enge Kopplung dereinzelnen Zustaumlnde an ihr jeweiliges Verhalten mit sich
12
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
Je nach Umfang und Komplexitaumlt des Systems kann es ein groszliger Nachteil sein dassalle Zustaumlnde samt ihres kompletten Verhaltens innerhalb eines Aufzaumlhlungstyps angege-ben werden Dieser liegt bekanntermaszligen innerhalb einer Uumlbersetzungseinheit und einerDatei Damit geht die lose Kopplung der verschiedenen Zustaumlnde teilweise verloren An-dererseits kann bei kleineren Systemen die houmlhere Uumlbersichtlichkeit und der geringerestrukturelle Mehraufwand auch ein Vorteil seinAls Auswirkung dieser Implementation ist weiterhin erwaumlhnenswert dass durch die
Benutzung eines Aufzaumlhlungstyps fuumlr das komplette Verhalten an keiner Stelle im Co-de irgendwelche expliziten Instanziierungen stehen Die einzigen Objekte die erzeugtwerden sind die zu Beginn erzeugten und statisch verfuumlgbaren Exemplare des Aufzaumlh-lungstyps
Zusammenfassung
+ enge Kopplung jedes Zustands mit seinem Verhalten
+ hohe Uumlbersichtlichkeit bei kleinen Systemen
+ keine strukturelle Komplexitaumlt auf Klassenebene
minus keine Aufteilung der Zustaumlnde in verschiedene Dateien moumlglich
6 Weitere AnsaumltzeDie in diesem Abschnitt behandelten Umsetzungen verfolgen weitere Herangehenswei-sen die sich von den bereits behandelten so sehr unterscheiden dass sie unserer Mei-nung nach erwaumlhnenswert sind Sie sind bis dato weniger praxiserprobt als die bereitsaufgefuumlhrten Loumlsungen haben aber dafuumlr spezielle Eigenschaften die bei bestimmtenProblemstellungen von Vorteil sein koumlnnen
61 Objektbasiertes ZustandsgeflechtBei diesem Ansatz gibt es anders als beim Zustandsmuster nicht fuumlr jeden konkreten Zu-stand eine Klasse sondern eine allgemeine Zustandsklasse Die Exemplare dieser Klassedienen dann als Modellierung der ZustaumlndeDie Aktionen werden als Enum externalisiert Es koumlnnen zur Laufzeit beliebig viele
Zustaumlnde erzeugt werden Jeder Zustand haumllt eine Abbildung von Aktionen auf Nach-folgezustaumlnde Es ist dann zur Laufzeit moumlglich den Nachfolgezustand eines Zustandesbei einer bestimmten Aktion zu setzen und wieder abzufragenDieser Ansatz ist nur dann implementierbar wenn die verschiedenen Zustaumlnde keine
individuelle Logik besitzen muumlssen Alles was die Zustaumlnde unterscheidet (hier die Hel-ligkeit) muss ihnen bei der Erzeugung uumlbergeben werden und somit in Form von Datenvorliegen Es waumlre wohl theoretisch denkbar den verschiedenen Zustaumlnden mittels Po-lymorphie unterschiedliches Verhalten zuzuordnen indem man unterhalb der Zustands-klasse wieder ein Zustandsmuster implementiert Das waumlre allerdings aus Designsicht
13
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
kaum zu rechtfertigen da in dem Fall auch gleich das Zustandsmuster haumltte implemen-tiert werden koumlnnenDie Spezifikation der moumlglichen Zustaumlnde und Uumlbergaumlnge geschieht hier in der Klasse
die den Kontext bildetDiese Umsetzung bietet als einzige der hier vorgestellten Varianten die Moumlglichkeit
das Zustandsverhalten zur Laufzeit zu aumlndern Alle anderen Vorgehensweisen spezifi-zieren die Zustaumlnde und Uumlbergaumlnge statisch zur Uumlbersetzungszeit Hier kann dagegenzu beliebigen Zeitpunkten in der Ausfuumlhrung das Zustandsverhalten veraumlndert werdenDiese Eigenschaft kann von Vorteil sein falls ein System modelliert werden soll dessenZustandsspezifikation sich tatsaumlchlich im Laufe der Zeit aumlndertAndererseits ist die fehlende statische Analysierbarkeit auch der groumlszligte Nachteil im
Vergleich zu anderen Loumlsungen Zur Uumlbersetzungszeit ist nicht feststellbar welche Zu-staumlnde existieren und welche Uumlbergaumlnge moumlglich sind Dadurch wird die Uumlberschaubar-keit und die Beherrschbarkeit des Systems verringertEine Umsetzung der Kippschalter-Lampe nach diesem Prinzip findet sich in Listing 6
62 Enum mit TransitionstabelleDiese Variante entspricht in etwa der bereits behandelten Enum-Umsetzung Hier erhal-ten die einzelnen Werte des Aufzaumlhlungstyps jedoch kein spezielles Verhalten in Formvon Code sondern jeder der Zustaumlnde bekommt seine moumlglichen Nachfolgezustaumlnde alsKonstruktorparameter uumlbergeben Im Konstruktor werden diese gesichert und spaumlter beiZustandswechseln ausgelesenBei der Erzeugung der Objekte die hinter den Enum-Werten stehen koumlnnen keine
Werte referenziert werden die im Enum erst nach dem zu erzeugenden Wert aufgezaumlhltwerden Aus diesem Grund werden die Nachfolgezustaumlnde als Strings uumlbergeben und ge-halten Beim Zustandswechsel wird mit valueOf der passende Wert des Enum ermitteltKonzeptuell sind die Unterschiede zur Standard-Enum-Umsetzung nicht sehr groszlig
Auszeichnend fuumlr diese Variante ist jedoch die Trennung von Spezifikation und Imple-mentationslogik Um Zustaumlnde hinzuzufuumlgen oder Uumlbergaumlnge zu veraumlndern muss keinCode-Geflecht angepasst werden die Spezifikation der Uumlbergaumlnge erfolgt quasi tabella-rischDas Kippschalter-Beispiel ist in Listing 7 auf diese Weise umgesetzt
7 ZusammenfassungEs existiert eine Vielzahl von Moumlglichkeiten zustandsbasierte Systeme in Java zu pro-grammieren die alle ihre Vor- und Nachteile haben Eine allgemeine eindeutige Emp-fehlung kann es nicht geben Es ist individuelles Feingefuumlhl gefragt wenn es darum gehtwelche Umsetzung in einer bestimmten Situation am besten geeignet istIn besonders einfachen Situationen in denen keine spaumltere Erweiterung zu erwarten
ist bietet evtl die naive Umsetzung das beste Verhaumlltnis von Aufwand und NutzenGibt es dagegen eine Vielzahl von Zustaumlnden die im Laufe der Zeit erweiterbar sein
soll und hat jeder Zustand ein komplexes eigenes Verhalten kann einer der Entwuumlrfe
14
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
nach dem Vorbild des Zustandsmusters die beste Loumlsung seinRechtfertigt die Situation den strukturellen Mehraufwand des Zustandsmusters nicht
ist ggf eine Umsetzung mit einem Aufzaumlhlungstyp oder eine der weiteren Moumlglichkeitendas Mittel der WahlWir hoffen dass mit den Erkenntnissen aus diesem Paper die noumltige Entwurfsentschei-
dung bewusst und in Kenntnis aller wichtigen Alternativen gefaumlllt werden kann
15
Quelltext-ListingsListing 1 Naive Umsetzung
1 public class Lampe
0 = Licht aus 1 = Halbe Helligkeit
5 2 = Volle Helligkeitprivate int zustand = 0
public void drueckeLinks() switch (zustand)
10 case 0 zustand = 2break
case 1 zustand = 0break
case 2 Zustand unveraumlndert15 break
default Systemoutprintln(Zustand fehlerhaft)
20 public void drueckeRechts() switch (zustand)
case 0 zustand = 1break
case 1 Zustand unveraumlndert25 break
case 2 zustand = 0break
default Systemoutprintln(Zustand fehlerhaft)
30
public double gibHelligkeit() double helligkeit = 00switch (zustand)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public class Lampe private enum LampeZustand LICHT_AUS HALBE_HELLIGKEIT VOLLE_HELLIGKEIT private LampeZustand zustand = LampeZustand LICHT_AUS public void drueckeLinks () if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand VOLLE_HELLIGKEIT else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS public void drueckeRechts () if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) zustand = LampeZustand LICHT_AUS else if ( zustand == LampeZustand LICHT_AUS ) zustand = LampeZustand HALBE_HELLIGKEIT public double gibHelligkeit () double helligkeit = 00 if ( zustand == LampeZustand LICHT_AUS ) helligkeit = 00 else if ( zustand == LampeZustand HALBE_HELLIGKEIT ) helligkeit = 05 else if ( zustand == LampeZustand VOLLE_HELLIGKEIT ) helligkeit = 10 return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Naive Umsetzung mit innerem AufzAtildecurrenhlungstyp Lampejava
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public LampeZustand_EnumTable drueckeLinks() 20 return valueOf(links)
public LampeZustand_EnumTable drueckeRechts() return valueOf(rechts)
25
public double gibHelligkeit()
26
Listings7EnumTableLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = LampeZustand LICHT_AUS public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeLinks () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle Lampejava
return helligkeit
30 LampeZustandjava
27
Listings7EnumTableLampeZustandjava
public enum LampeZustand Zustand(folgezustandLinks folgezustandRechts helligkeit) LICHT_AUS ( VOLLE_HELLIGKEIT HALBE_HELLIGKEIT 00 ) HALBE_HELLIGKEIT ( LICHT_AUS HALBE_HELLIGKEIT 05 ) VOLLE_HELLIGKEIT ( VOLLE_HELLIGKEIT LICHT_AUS 10 ) private final String links private final String rechts private final double helligkeit private LampeZustand ( String links String rechts double helligkeit ) this links = links this rechts = rechts this helligkeit = helligkeit public LampeZustand_EnumTable drueckeLinks () return valueOf ( links ) public LampeZustand_EnumTable drueckeRechts () return valueOf ( rechts ) public double gibHelligkeit () return helligkeit
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Externer Zustand als AufzAtildecurrenhlungstyp mit Transitionstabelle LampeZustandjava
Literatur[FFBS04] Freeman Elisabeth Freeman Eric Bates Bert Sierra Kathy Head
First Design Patterns Sebastopol OrsquoReilly Media 2004
[GHJV95] Gamma Erich Helm Richard Johnson Ralph Vlissides John DesignPatterns Elements of Reusable Object-Oriented Software Boston Addison-Wesley 1995
[GJSB05] Gosling James Joy Bill Steele Guy Bracha Gilad Java LanguageSpecification Third Edition Boston Addison-Wesley 2005
28
Deckblatt
Inhaltsverzeichnis
Kurzfassung
Einfuumlhrung
Motivation
Thematische Eingrenzung
Ein einfaches zustandsbasiertes System
Loumlsungsansatz 1 Die naive Umsetzung
Entwurf
Eigenschaften
Loumlsungsansatz 2 Das Zustandsmuster
Beschreibung des Musters
Entwurf
Dezentrale Transitionsverwaltung
Zentrale Transitionsverwaltung
Eigenschaften
Verwandte Muster
Loumlsungsansatz 3 Erweiterte Moumlglichkeiten von Java-Enums
Entwurf
Eigenschaften
Weitere Ansaumltze
Objektbasiertes Zustandsgeflecht
Enum mit Transitionstabelle
Zusammenfassung
Anhang
Quelltext-Listings
1 Naive Umsetzung
2 Naive Umsetzung mit innerem Aufzaumlhlungstyp
3 Zustandsmuster mit dezentraler Transitionsverwaltung
4 Zustandsmuster mit zentraler Transitionsverwaltung
5 Externer Zustand als Aufzaumlhlungstyp
6 Objektbasiertes Zustandsgeflecht
7 Externer Zustand als Aufzaumlhlungstyp mit Transitionstabelle
Literatur
Listing 3 Zustandsmuster mit dezentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 public Lampe() zustand = new LampeZustandLichtAus()
public void drueckeLinks() 10 zustand = zustanddrueckeLinks()
public void drueckeRechts() zustand = zustanddrueckeRechts()
15
public double gibHelligkeit() return zustandgibHelligkeit()
20
Lampejava
1 public interface LampeZustand
public LampeZustand drueckeLinks()
public LampeZustand drueckeRechts()5
public double gibHelligkeit()
LampeZustandjava
1 public class LampeZustandLichtAus implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandVolleHelligkeit()
5
public LampeZustand drueckeRechts() return new LampeZustandHalbeHelligkeit()
10
public double gibHelligkeit() return 00
LampeZustandLichtAusjava
18
Listings3ZustandDezentralLampejava
public class Lampe private LampeZustand zustand public Lampe () zustand = new LampeZustandLichtAus () public void drueckeLinks () zustand = zustand drueckeLinks () public void drueckeRechts () zustand = zustand drueckeRechts () public double gibHelligkeit () return zustand gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung Lampejava
Listings3ZustandDezentralLampeZustandjava
public interface LampeZustand public LampeZustand drueckeLinks () public LampeZustand drueckeRechts () public double gibHelligkeit ()
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandjava
Listings3ZustandDezentralLampeZustandLichtAusjava
public class LampeZustandLichtAus implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandVolleHelligkeit () public LampeZustand drueckeRechts () return new LampeZustandHalbeHelligkeit () public double gibHelligkeit () return 00
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandLichtAusjava
1 public class LampeZustandHalbeHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return new LampeZustandLichtAus()
5
public LampeZustand drueckeRechts() return this
10
public double gibHelligkeit() return 05
LampeZustandHalbeHelligkeitjava
1 public class LampeZustandVolleHelligkeit implements LampeZustand
public LampeZustand drueckeLinks() return this
5
public LampeZustand drueckeRechts() return new LampeZustandLichtAus()
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)
public class LampeZustandHalbeHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return new LampeZustandLichtAus () public LampeZustand drueckeRechts () return this public double gibHelligkeit () return 05
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandHalbeHelligkeitjava
public class LampeZustandVolleHelligkeit implements LampeZustand public LampeZustand drueckeLinks () return this public LampeZustand drueckeRechts () return new LampeZustandLichtAus () public double gibHelligkeit () return 10
Julian Fietkau Janina Nemec
Modellierung zustandsorientierter Systeme in Java Das Zustandsmuster Varianten und Alternativen
Zustandsmuster mit dezentraler Transitionsverwaltung LampeZustandVolleHelligkeitjava
Listing 4 Zustandsmuster mit zentraler Transitionsverwaltung 1 public class Lampe
private LampeZustand zustand
5 private static final LampeZustand zustandLichtAus =new LampeZustandLichtAus()
private static final LampeZustand zustandHalbeHelligkeit =new LampeZustandHalbeHelligkeit()
private static final LampeZustand zustandVolleHelligkeit =10 new LampeZustandVolleHelligkeit()
public Lampe() zustand = new LampeZustandLichtAus()
15
public void drueckeLinks() if(zustand == zustandLichtAus)