UML-Zustandsdiagramm

Was beschreibt das UML-Zustandsdiagramm?

Das UML-Zustandsdiagramm modelliert ein System unter folgenden Gesichtspunkten:

  • die unterschiedlichen Zustände, die ein Objekt/System im Verlauf der Lebenszeit einnehmen kann,
  • welche Ereignisse den Zustandswechsel hervorrufen und
  • welche Aktionen in den jeweiligen Zuständen möglich sind.

Als Verhaltensdiagramm stehen die dynamischen Vorgänge eines Systems im Fokus.

Grundelemente des Zustandsdiagramms

Zustandsdiagramme bestehen in wesentlichen aus Knoten und gerichteten Kanten, im Wesentlichen:

  • Startzustand,
  • Endzustand,
  • Transitionen und
  • Zustände
Ein einfaches UML-Zustandsdiagramm mit den Zuständen “hungrig” und “satt”
Ein einfaches UML-Zustandsdiagramm mit den Zuständen “hungrig” und “satt”

Welche Einsatzgebiete haben UML-Zustandsdiagramme?

Zustandsdiagramme werden v.a. in Planungs- und in der Testphase des Softwareentwicklungsprozesses genutzt, um graphisch die Frage zu modellieren:

Wie verhält sich mein System in einem bestimmten Zustand bei Eintritt bestimmter Ereignisse?

Wie bei allen UML-Diagrammen sollte auch hier im Fokus stehen: Wem möchte ich mit meinem Zustandsdiagramm was mitteilen? Adressat und Nachricht müssen immer berücksichtigt werden.

Detailreichtum, Komplexität der Notationselemente und Namensgebung müssen entsprechend dem Adressaten und der Intention angepasst werden. Dies kann auch von Phase zu Phase variieren:

  • In der Analysephase werden die Zustandsabfolgen und -übergänge der Geschäftsprozesse dargestellt und einzelne Szenarien der Anwendungsfälle (oder übergeordnete Zustandsfolgen) präzisiert. Zustandsdiagramme eignen sich besonders gut, um ereignisgesteuerte Abläufe wie etwa die Navigation in einer (graphischen) Benutzeroberfläche ([G]UI) zu modellieren. Die Übergänge der einzelnen Masken, Fenster u.ä. kann im Dialog mit anderen Projektbeteiligten, dem Auftraggeber, der Fachdomäne erarbeitet werden.

  • In der Entwurfsphase kann das Zustandsdiagramm dabei helfen, Sonderfälle in der Ereignisabfolge systematisch zu strukturieren: Wann sollen die Objekte meines Systems anders reagieren? Wie kann dies modelliert - und später implementiert - werden?

  • In der Testphase kann an Hand der Zustände und herausgearbeiteten Transitionen ein Grundgerüst an Testfällen erstellt werden. Es ist in der Regel ratsam, jeden Zustand und jede Transition mit mindestens einem Testfall abzudecken.

Bestandteile eines UML-Zustandsdiagramms

Grundsätzlich besteht ein Zustandsdiagramm aus Knoten (Zuständen) und gerichteten Kanten (Transitionen):

Startzustand

Einstiegspunkt des Diagramms ist der Startzustand (initial state). Er legt fest, welchen Zustand das modellierte System am Beginn einnimmt. Der Startzustand wird mit einem ausgefüllten Kreis notiert.

Der Startzustand
Der Startzustand

Da das System sich nie im Startzustand selbst befindet spricht man hier von einem Pseudozustand. An dem Übergang (Transition) vom Startzustand zum ersten regulären Zustand dürfen keine Bedingungen (guards) notiert werden - sofern dieser Zustandsübergang mit einer Instanziierung (Objekterzeugung) zusammenfällt könnte jedoch der event notiert werden, der die Objekterzeugung triggert.

Ein modelliertes System kann auf jeder Ebene nur einen Startzustand haben.

Zustände

Ein einfacher Zustand (simple state) fasst Situationen zusammen, in denen sich das modellierte Objekt die selben Aktionen und Zustandsübergänge ausführen kann. Zustände werden in Rechtecken mit abgerundeten Ecken notiert, in denen mindestens der Name des Zustands steht.

Der Zustand hungrig
Der Zustand hungrig

In der unteren Hälfte eines Zustands können (optional) innere Aktionen notiert werden. Innere Aktionen sind alle Aktionen, die keinen Zustandswechsel hervorrufen. Die Trennlinie kann weggelassen werden, wenn nur der Zustandsname angegeben wird.

Transitionen

Die gerichteten Kanten (Pfeile) des Zustandsdiagramms symbolisieren Zustandsübergänge (Transitionen).

Die Zustände hungrig und satt
Die Zustände hungrig und satt

Durch Ereignisse (events) werden Zustandsübergänge (transitions) ausgelöst. Transitionen zeigen von einem Quell- zu einem Zielzustand.

An Transitionen können drei Eigenschaften notiert werden: event [guard] /effect:

Die Zustände hungrig und satt
Die Zustände hungrig und satt
  • Events sind die Trigger, die den Zustandsübergang auslösen (im Beispiel oben: essen).

  • Guards sind die Bedingungen, die geprüft werden, nachdem ein events eingetreten ist. Trifft ein guards zu wird der Zustandübergang durchgeführt. Diese Bedingungen werden in eckigen Klammern nach den events notiert (im Beispiel: [wenn Essen da]).

  • Effekte (effects) werden aussgeführt, während der Zustandsübergang stattfindet. Nach Abschluss des Effekts ist der Zustandsübergang erfolgt. Effekte werden an der Kante nach einem Schrägstrich notiert (im Beispiel: /schmatzen()). Häufig handelt es sich hierbei um Methoden oder Funktionen des modellierten Systems, diese werden mit runden Klammern abgeschlossen.

Endzustand

Der Endzustand (final state) ist ein regulärer Zustand, in dem sich das System am Ende befindet, aus dem es aber nicht mehr in andere Zustände innerhalb der Modellierung wechseln kann.

Der Endzustand
Der Endzustand

Im Gegensatz zu Startzuständen gelten Endzustände als reguläre Zustände. Daraus folgt: es kann mehrere Endzustände oder mehrere Transitionen zu Endzuständen geben und an diesen können auch events, guards oder effects notiert werden.

Entscheidungsknoten: choices und junctions

Statische Verzweigungen mit junctions

Die einfachste Art, eine Verzweigung zu modellieren, ist es, mehrere Transaktionen zu notieren. Wird der event aktiviert, so wird anschließend der guard geprüft, dann der effect ausgelöst und der Zustandsübergang ausgeführt:

Der Entscheidungsknoten
Der Entscheidungsknoten

Beispiel: Vor dem Zustandsübergang befindet sich das System in State1, und es gilt a==1. Wenn trigger eintritt wird zunächst geprüft, ob a==1 - das trifft zu, also wird die Transition Richtung State2 ausgeführt und dabei a um eins erhöht.

Da sich in diesem Beispiel event und effect für die unterschiedlichen Transitionen nicht unterscheidet, gibt es eine Kurzform, die diese beiden Transaktionen zusammenfasst: es wird ein junction-Pseudostate durch einen Kreis notiert.

Der Entscheidungsknoten
Der Entscheidungsknoten

Wichtig hierbei ist: der guard der beiden ausgehenden Kanten wird geprüft bevor (!) der effect (hier a++) ausgelöst wird. Man spricht hier daher von einem static conditional branch also einer statischen bedingten Verzweigung. Junctions stellen nur eine Kurzschreibweise für mehrere einzelne Transaktionen dar.

Dynamsiche Verzweigungen mit choices

Im Gegensatz zu den statischen junctions werten dynamische Entscheidungsknoten (choices) die guards erst beim Erreichen des Entscheidungsknoten aus. Choices werden durch eine i.d.R. leere Raute dargestellt. Vor der Wahl der ausgehenden Transition wurde also der effect bereits ausgeführt. In unserem Beispiel sähe das so aus:

Der Dynamische Verzweigungen - der choice-Entscheidungsknoten
Der Dynamische Verzweigungen - der choice-Entscheidungsknoten

Vor dem Zustandsübergang befindet sich das System in State1, und es gilt a==1. Wenn trigger eintritt wird zunächst der effect a++ ausgeführt (es gilt also jetzt a==2). Erst jetzt werden die guards überprüft: nur der else-Zweig wird als true ausgewertet, die Transition findet also in Richtung State3 statt. Wir erreichen also in diesem Beispiel mit choices einen anderen Zustand als bei junctions!

Da im Fall einer choice der Quellzustand bereits verlassen wurde, wenn der guard ausgewertet wird, muss sichergestellt sein, dass für jeden möglichen Fall mindestens ein guard erfüllt ist, da sich das System sonst im Pseudozustand befindet - also nicht korrekt modelliert wurde. Am einfachsten erreicht man dies, in dem an einer der ausgehenden Transaktionen als guard else notiert wird.

Innere Aktionen

Für Zustände kann ein inneres Verhalten (internal behavior) sowie innere Transitionen modelliert werden.

Die inneren Aktionen entry/do/exit sowie eigene
Die inneren Aktionen entry/do/exit sowie eigene

Es gibt drei Arten von innerem Verhalten:

  • die entry-Aktivitäten werden immer dann ausgeführt, wenn der Zustand über eine externe Transition betreten wird.

  • die exit-Aktivitäten werden immer dann ausgeführt, wenn der Zustand über eine externe Transition verlassen wird.

  • do-Aktivitäten werden nach den entry-Aktivitäten ausgeführt. Sofern Sie abgeschlossen werden, triggern Sie einen completion event. Completion events wiederum triggern Transitionen ohne eigene Trigger, deren guard als wahr ausgewertet wird. Das passiert genau einmal, am Ende der do-Aktivität. (Im obigen Beispiel: wenn im Zustand wach arbeiten beendet wurde wird ein completion event getriggert und geprüft, ob der guard [Müdigkeit>Wille] zutrifft. Falls dem so ist wird der Zustandsübergang eingeleitet).

Im Zustand “wach” stellen Kaffee trinken, arbeiten und Zähne putzen inneres Verhalten dar.

Neben diesen drei Arten inneren Verhaltens gibt es noch innere Transitionen: diese entsprechen den externen Transitionen mit dem Unterschied, dass sie weder exit noch entry-Verhalten triggern, noch einen Zustandswechsel hervorrufen.

Der Trigger “Vollmond” löst bei Werwölfen zwar keinen Zustandswechsel aus (der Zustand bleibt “schlafend”), triggert aber eine innere Aktion (Schlafwandeln). Weder hört das System auf zu träumen, noch würden in diesem Fall die Augen geöffnet und wieder geschlossen.

Im Gegensatz dazu werden bei externen Transitionen immer die modellierten entry- und exit-Verhalten ausgeführt. Das gilt auch, wenn die externe Transition wieder zum Ausgangszustand zurückführt. Wenn man im Schlaf aufgeschreckt wird, würde im dem obigen Modell:

  1. der Trigger “aufgeschreckt” registriert,
  2. geprüft, ob der guard zutrifft (zeit<weckzeit),
  3. das do-Verhalten unterbrechen und exit-Verhalten “Augen auf” ausgeführt,
  4. der effect der Transition ausgeführt: “weiterschlafen”,
  5. das entry-Verhalten “Augen zu” ausgeführt und
  6. das do-Verhalten starten: träumen.

Zusammengesetzte Zustände (composite state)

Zusammengesetze Zustände bilden innere Subzustände ab. Es bestehen zwei Möglichkeiten, diese mit UML zu modellieren:

In einem gemeinsamen Diagramm werden die zusammengesetzten Zustände und ihre Subzustände dargestellt:

Zusammengesetzte Zustände und Subzustände
Zusammengesetzte Zustände und Subzustände

Die beiden Ebenen (zusammengesetzter Zustand / Subzustände) können in gesonderten Diagrammen dargestellt werden. Hierbei wird im zusammengesetzten Zustand durch ein Symbol notiert, dass sich dieser aus Subzuständen zusammensetzt. Das Symbol soll zwei Zustände und eine Transition stilisiert darstellen.

Zusammengesetzter Zustand in Darstellung ohne Subzustände
Zusammengesetzter Zustand in Darstellung ohne Subzustände

Die Subzustände selbst würden in diesem Fall in einem eigenen Zustandsdiagramm dargestellt. Das Diagramm wir überschrieben mit “stm” für State Machine mit dem Namen des zusammengesetzten Zustands:

Die Subzustände eines zusammengesetzten Zustands als eigenes Diagramm
Die Subzustände eines zusammengesetzten Zustands als eigenes Diagramm

Es muss für jede Ebene gesondert erfasst werden, in welchem Zustand sich das System zu Beginn befindet bzw. aus welchem Zustand heraus das System beendet wird:

Start- und Endzustand für zusammengesetzte Zustände
Start- und Endzustand für zusammengesetzte Zustände

Dabei können Subzustände direkt mit Transitionen erreicht werde: im Beispiel unten ist der Startzustand des Systems immer wach.hungrig, den Zustand schlafend kann man nur aus den Subzuständen wach.satt und wach.überfressen erreichen. Wenn man vom Zustand schlafend per Wecker geweckt wird, nimmt man wieder den Subzustand von wach ein, den man vor dem Einschlafen hatte (also satt oder überfressen). Das wird im UML-Zustandsdiagramm mit dem History Symbol (H) gekennzeichnet. Sofern der betreffende zusammengesetzte Zustand bislang nicht betreten wurde ist das System in dem Subzustand, auf den die ausgehende Transition des History-Pseudozustands zeigt (im Beispiel also hungrig). Diese Fall nennt sich “flache Historie”, da nur eine Ebene berücksichtigt wird.

Flache Historie eines zusammengesetzten Zustands
Flache Historie eines zusammengesetzten Zustands

Eine Erweiterung dazu stellt die “tiefe Historie” dar. Hierbei wird der Subzustand nicht nur auf der ersten Ebene, sondern so tief wie möglich wiederhergestellt. Gekennzeichnet wird dies mit dem (H*) Symbol. Wenn der Wecker klingelt und der letzte Subzustand von wach war hungrig, dann würde das System auch unmittelbar wieder in den vorigen Subzustand von hungrig wechseln (also vegetarisch oder omnivor):

tiefe Historie
tiefe Historie

Der Ausgangszustand ist - wie die beiden Transitionen von den (H)- bzw. (H*) Pseudozuständen zeigen - hungrig und vegetarisch.

Regionen in zusammengesetzten Zuständen

Eigentlich ist auf jeder Ebene eines UML-Zustandsdiagramms immer nur ein Zustand aktiv. Es können aber bei Subzuständen Regionen definiert werden, in denen jeweils einer der verzeichneten Zustände aktiv ist:

tiefe Historie
tiefe Historie

Weitere Literatur zu UML-Zustandsdiagrammen

  • als Primärquelle: die UML Spezifikation der Object Management Group Definition des Standards, jedoch nicht für Endnutzer aufbereite. Die für das Zustandsdiagramm relevanten Abschnitte finden sich unter dem Kapitel 14.2 Behavior StateMachine (S. 305 bzw. PDF_Seite 347). Die Notationselemente finden sich ab S. 708 (im PDF S. 750) https://www.omg.org/spec/UML

  • für den Einstieg: Martina Siedl, Marion Brandsteidl, Christian Huemer, Gerti Kappel: UML@Classroom, dpunkt Verlag, Heidelberg 2012 Gut zu lesende Einführung in die wichtigsten UML-Diagramme, Empfehlung für den Einstieg - (nicht auf Stand der neusten UML-Version, das betrifft aber nur Detailfragen)

  • für Lesefaule: Die Vorlesungsreihe der Technischen Uni Wien (zu UML@Classroom) kann hier angeschaut werden (Videos, Folien): http://www.uml.ac.at/de/lernen

  • als Nachschlagewerk: Christoph Kecher, Alexander Salvanos: UML 2.5 – Das umfassende Handbuch, Rheinwerk Bonn 2015, ISBN 978-3-8362-2977-7, ein sehr umfangreiches Nachschlagewerk zu allen UML-Diagrammen

  • als Cheatsheet: die Notationsübersicht von oose.de: https://www.oose.de/wp-content/uploads/2012/05/UML-Notations%C3%BCbersicht-2.5.pdf

  • UML und Software Engineering: Chris Rupp, Stefan Queins & die SOPHISTen: UML2 glasklar, Hanser Verlag, München 2012; ISBN 978-3-446-43057-0 Schwerpunkt: Einbindung von UML-Diagrammen in den Softwareentwicklungszyklus

  • Zur Zertifizierungs-Vorbereitung: M. Chonoles: OCUP 2 Certification Guide , Morgan Kaufmann Verlag, Cambridge 2018, ISBN 978-0-12-809640-6 Informationen zur Zertifizierung nach OMG Certified UML Professional 2™ (OCUP 2™): Foundation Level

Software zur Erzeugung von UML-Zustandsdiagrammen

Quellen und offene Ressourcen (OER)

Die Ursprungstexte (als Markdown), Grafiken und zugrunde liegende Diagrammquelltexte finden sich (soweit möglich in weiterbearbeitbarer Form) in folgendem git-Repository:

https://gitlab.com/oer-informatik/uml/umlzustand.

Sofern nicht explizit anderweitig angegeben sind sie zur Nutzung als Open Education Resource (OER) unter Namensnennung (H. Stein, oer-informatik.de) freigegeben gemäß der Creative Commons Namensnennung 4.0 International Lizenz (CC BY 4.0).

Creative Commons Lizenzvertrag

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: