UML-Zustandsdiagramme mit PlantUML erstellen
PlantUML ist ein vielseitig nutzbares Tool, um testbasiert versionierbare (UML-)Diagramme zu erstellen. Aus einfachen Quelltexten lassen sich so UML-Diagramme als PNG, ASCII-Art oder SVG erstellen. PlantUML ist als Webservice verfügbar (z.B. https://www.planttext.com/), in vielen IDEs (als Plugin) integriert und wird von einigen Markdown-Interpretern direkt umgewandelt. Allgemeine weiter Infos zu PlantUML finden sich hier: https://www.planttext.com/
Da die Anleitung zu UML-Diagrammen nicht immer den aktuellen UML-Standard im Blick haben, versuche ich hier praktische Tipps zu geben, wie standardkonforme UML-Zustandsdiagramme mit PlantUML erstellt werden können.
Grundbausteine des UML-Zustandsdiagramms
UML-Zustandsdiagramme bestehen im Wesentlichen aus einem Startzustand, einzelnen Zuständen, einem Endzustand (optional) sowie Transitionen, die die Zustände verbinden. In PlantUML werden Zustände zunächst deklariet (state Zustand1
oder bei längerem Namen mit Alias state "Dargestellter Name des \nZustands 2" as Zustand2
) und die verbindenden Transitionen in Zeilen mit stilisiertem ASCII-Pfeil beschrieben:
state hungrig
state "satt" as wohlgenährt
hungrig -> wohlgenährt

Start- und Endzustand werden in PlantUML mit [*]
notiert. An Hand der Pfeilrichtung wird automatisch erkannt, ob es mit sich um einen Start- oder einen Endzustand handelt:
left to right direction
[*] --> Zustand1
Zustand1 --> [*]

Transitionen
An den Transitionen können - wie in der UML üblich - Event (Trigger), Guard (Bedingung) und Effekt (Aktion während der Transition) notiert werden (in der Form: startzustand -> zielzustand: Trigger [Guard] / Effekt
). In PlantUML sieht es wie folgt aus:
state hungrig
state satt
hungrig -right-> satt : essen [wenn Essen da] /schmatzen()

Innere Aktionen der Zustände
Die Zustände können mit inneren Aktionen versehen werden, sie werden mit Hilfe des Zustandsnamens und folgendem Doppelpunkt notiert - entweder nach dem Muster
Event [Guard] / interneAktion
oder entsprechend der drei internen Events: entry
, do
, exit
:
state schlafend
schlafend : entry/Augen zu
schlafend : do/träumen
schlafend : exit/Augen auf
schlafend : Vollmond [Werwolf == true]/Schlafwandeln
state wach
wach : entry/Kaffee trinken
wach : do/arbeiten
wach : exit/Zähneputzen
wach -right-> schlafend : [Müdigkeit > Wille] /Schlafanzug anziehen
schlafend -left-> wach : Weckerklingeln [zeit>=weckzeit] /aufstehen
schlafend -left-> schlafend : aufschrecken [zeit<weckzeit] /weiterschlafen

Verzweigungen (Choices)
Um dynamische Entscheidungen (Choices) in PlantUML einzubinden muss die Raute als Pseudozustand mit dem Stereotyp <<choice>>
deklariert werden und danach wie jeder andere Zustand eingebunden werden:
state State1: entry/a=1
state entscheidung <<choice>>
state State2
state State3
State1 -> entscheidung : trigger /a++
entscheidung -> State2 :[a == 1]
entscheidung -> State3 :[else]
Wichtig: bei Choices wird der Guard erst nach dem Effekt ausgewertet. In folgendem Beispiel wird a (in State1
: a = 1) also erst hochgezählt (a++, also a=2) und dann der Guard ausgewertet ((a == 1) = false) - es wird also immer die [else]
-Transition genommen und State3
erreicht.

Kreuzungen (Junctions)
Sofern die Guards bereits vor den Effekten ausgewertet werden sollen (statische Entscheidungen / junctions), müssen im UML-Diagramm Knoten (ausgefüllte Kreise) notiert werden. In PlantUML ist das aber nicht möglich. Daher müssen diese zusammenhängenden Transitionen als einzelne Transitionen mit identischem Trigger und unterschiedlichen Guards modelliert werden:
state State1
State1 : entry/ a=1
state State2
state State3
State1 -right-> State2 : trigger[a == 1]/a++
State1 --right-> State3 :trigger[else]/a++

Zusammengesetzte Zustände (composed states)
Mit Hilfe von geschweiften Klammern können composed states beliebig verschachtelt werden:
state schlafend
state wach{
state hungrig
state satt
hungrig -> satt : gegessen
satt -> hungrig : verdaut
}
schlafend -> wach : Wecker
wach -> schlafend : einschlafen

Wenn Sie nur als Verweis referenziert werden sollen muss man mit PlantUML allerdings etwas zaubern, um das Symbol, das zwei Zustände zeigt in die Ecke zu schreiben (Workaround: Tab (Unicode #9) zur Einrückung und Unendlich-Symbol (Unicode #8734) zur Darstellung der Unterzustände):
@startuml
state "zusammengesetzter\nZustand" as subState
subState: 				<b>∞</b>
@enduml

Regionen in zusammengesetzten Zuständen
Mit Hilfe von zwei Bindestrichen lassen sich Regionen mit Unterzuständen definieren.
@startuml
left to right direction
state wach {
[*] --> zufrieden
zufrieden --> unzufrieden : Sonne
unzufrieden --> zufrieden : Regen
--
[*] --> neugierig
neugierig --> gelangweilt : warten
gelangweilt --> neugierig : loslegen
}
@enduml

Improvisationen für nicht vorhandene Notationselemente (History / Terminator)
Nutzt man die erweiteten PlantUML-Funktionen, so lassen sich auch Notationselemente wie der Terminator (Beenden des Zustandsautomaten) und die Speicherfunktion eines Unterzustands (History) abbilden:
Über sprite lassen sich beliebige pngs als Base64url einfügen, die per java -jar plantuml.jar -encodesprite 16z test.png umgewandelt werden und per <$spriteName> angesprochen werden. Der Terminator wird als sprite in einen Zustand geschrieben, dessen Ränder und Schrift per Stereotyp auf weiß gestellt sind. Darüber hinaus wurden auch alle Notizenzettel auf weiß gestellt, so dass in diesen Boxen die Regionsnamen und das History-Objekt einigermaßen notationskonform dargestellt werden kann. Notizen sind so allerdings nicht mehr möglich.
@startuml
left to right direction
skinparam state {
BackgroundColor<<terminate>> White
FontColor<<terminate>> White
BorderColor<<terminate>> White
}
skinparam NoteBorderColor White
skinparam NoteBackgroundColor White
skinparam stateShape start
skinparam shadowing false
sprite $history [30x30/16z] bTE54OKm50NHxM3xh_OBDfQTHoxEGQAyZLV2dfEmjIjzhP2iaApGBCluFDH7MUe9jWfIoevUsTVz_quredLkIKg77cpMOUGawpHYUxJFCsNE5m
sprite $terminator [30x30/16z] RSat0G0n5CMmp-3nHtjbygBqMDlEO_-8WJ4m5dOJmILoeH-nFx52h17ZK1oQGxCnDSR2s7ZaQWm4L_eO-neBm9An6993S0WEpIy
skinparam NoteBorderColor White
skinparam NoteBackgroundColor White
state wach {
note left of zufrieden : [glücklich]
[*] --> zufrieden
zufrieden --> unzufrieden : Sonne
unzufrieden --> zufrieden : Regen
note right of unzufrieden : <$history>
unzufrieden --> [*] : einschlafen
--
note left of neugierig : [interessiert]
[*] --> neugierig
neugierig --> gelangweilt : warten
gelangweilt --> neugierig : loslegen
gelangweilt -->end<<terminate>> :totlangweilen
end : <$terminator>
}
@enduml
Geerbte Zustände
Auch bei Zuständen gibt es eine Erbfolge - von Elternzuständen geerbte Zustände werden mit gestrichelter Linie dargestelle - in PlantUML folgendermaßen:
@startuml
state gererbterZustand ##[dashed] {
}
@enduml
plantUML-Webservice zur Diagrammerzeugung nutzen
PlantUML bietet einen Webservice, der Diagramme unmittelbar online rendert.
Variante 1: Codierter Quelltext: PlantUML kodiert den Quelltext, um ihn so über den Webservice zugänglich (und bearbeitbar) zu machen. Die URL ist in diesem Fall wie folgt aufgebaut: http://www.plantuml.com/plantuml/AUSGABEFORMAT/CODIERTERQUELLTEXT wobei als AUSGABEFORMAT
png
,svg
,eps
,epstext
undtxt
genutzt werden kann. Wird als AUSGABEFORMATuml
gewählt erhält man den bearbeitbaren Quelltext.Variante 2: Editierbare Links lassen sich auch über den Service von planttext.com erstellen, sie nutzen die selbe Quelltextcodierung und URLs nach dem Muster: https://www.planttext.com/?text=CODIERTERQUELLTEXT Auch in den erzeugten PNG-Dateien wird der codierte Quelltext als Titel hinterlegt, so dass sie sich relativ einfach später weiterverarbeiten lassen.
Variante 3: Quelltext direkt online rendern: der PlantUML-Quelltext ist online als Resource verfügbar und soll gerendert ausgegeben werden. Hierzu muss eine URL nach dem Muster: http://www.plantuml.com/plantuml/proxy?fmt=AUSGABEFORMAT&src=https://URL_PLANTUMLSOURCE erstellt werden, wobei als AUSGABEFORMAT
png
,svg
,eps
,epstext
undtxt
genutzt werden kann. Diese Funktion scheint derzeit deaktiviert zu sein oder nur Entwicklern vorbehalten.
plantUML-Formatierung: Aufhübschen von UML-Diagrammen
Über Skins bietet PlantUML die Möglichkeit, die Diagramme in Schriftart, Farben und Aussehen individuell anzupassen.
Ich nutze für meine Diagramme derzeit die folgenden Einstellungen:
skinparam style strictuml
skinparam shadowing true
skinparam DefaultFontName "Lucida Sans Typewriter"
skinparam State{
BackgroundColor snow
BorderColor DarkSlateBlue
DiamondBackgroundColor ghostwhite
DiamondBorderColor DarkSlateBlue
}
skinparam Activity{
DiamondBackgroundColor ghostwhite
DiamondBorderColor DarkSlateBlue
}
skinparam Note{
BorderColor DarkSlateBlue
BackgroundColor LightYellow
}
skinparam ArrowColor DarkSlateBlue
skinparam lineType ortho
Codebeispiel: ( online bearbeitbar )
UML-Zustandsdiagramme per Formatierung als Entwurf kennzeichnen
Um den Entwurfscharakter eines Diagramms zu unterstützen kann ein Layout verwendet werden, dass Handschrift ähnelt. Besonders wirkungsvoll ist das, wenn auch die Schrift authentisch handschriftlich aussieht. Dies ist z.B. bei der Schriftart “FG Virgil” der Fall (diese muss aber auf dem System installiert sein). Welche Schriften das jeweilige System bietet lässt sich mit dem PlantUML-Befehl listfonts
anzeigen. Wichtig ist: sofern eine Vektorgrafik ausgegeben wird (svg, eps) muss die Schrift auf allen anzeigenden Computern vorhanden sein, andernfalls werden Ersatzschriftarten verwendet.
Die ensprechenden Skin-Parameter sind:
skinparam style strictuml
skinparam DefaultFontName "FG Virgil"
skinparam handwritten true
skinparam monochrome true
skinparam packageStyle rect
skinparam shadowing false
Das Ergebnis sieht dann etwa so aus:

Diagramme vereinheitlichen und Formatierung auslagern
Damit nicht alle PlantUML-Diagramme die selben skinparam
-Sequenzen am Beginn der plantUML-Datei nennen müssen, kann eine zentrale Konfigurationsdatei eingebunden werden, die die Formatierungen enthält:
!includeurl https://PATH.TO/MY/UMLSEQUENCE_CONFIG.cfg
Alle Befehle in dieser Datei werden ausgeführt, als stünden sie in der umgebenden PlantUML-Datei. Um ein einheitliches Layout zu erreichen ist diese Funktion sehr praktisch!
Links
Es finden sich zahlreiche Quellen und Dokumentationen zu PlantUML im Netz, erwähnenswert sind u.a.:
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).