Zum Inhalt springen

13. Dynamik-Modellierung

Zu Zen-Modus wechseln

Das Klassendiagramm aus Kapitel 12 beantwortet die Frage, wer in einem System existiert: Klassen, Attribute, Beziehungen. Es sagt nichts darüber, was passiert, wenn das Programm läuft: in welcher Reihenfolge Objekte einander aufrufen, welche Zustände ein Objekt durchläuft, wie ein Geschäftsablauf von der Eingabe bis zum Ergebnis verläuft. Diese zeitliche Dimension heißt die Dynamik eines Systems.

Die UML stellt dafür mehrere Diagrammarten bereit; die drei wichtigsten sind Gegenstand dieses Kapitels. Jede beantwortet eine andere Frage:

Diagrammartbeantwortettypischer Einsatz
SequenzdiagrammWer ruft wen in welcher Reihenfolge auf?Zusammenspiel mehrerer Objekte in einem konkreten Ablauf
ZustandsdiagrammWelche Zustände hat ein Objekt, und was löst Übergänge aus?Objekte mit Lebenszyklus (Player, Verbindung, Bestellung)
AktivitätsdiagrammWie verläuft ein Arbeitsablauf mit Entscheidungen?Geschäftsprozesse, Algorithmen auf hoher Ebene

Die Wahl der passenden Diagrammart ist selbst ein Lernziel: Nicht jeder Ablauf ist ein Sequenzdiagramm, und ein Diagramm der falschen Art beantwortet die gestellte Frage nicht.

Ein Sequenzdiagramm zeigt einen konkreten Durchlauf durch das System: welche Objekte beteiligt sind und welche Nachrichten (Methodenaufrufe) sie in welcher Reihenfolge austauschen.

Die Bestandteile: Oben stehen die Beteiligten (Objekte oder Akteure), von jedem hängt eine durchgezogene Lebenslinie nach unten; die Zeit läuft von oben nach unten. Pfeile zwischen den Lebenslinien sind Nachrichten: durchgezogen mit gefüllter Spitze für synchrone Aufrufe, gestrichelt für Antworten. Schmale Rechtecke auf der Lebenslinie (Aktivierungsbalken) zeigen, wann ein Objekt gerade arbeitet.

Als Beispiel der Export eines Assets aus der Mediendatenbank (Kapitel 6), ausgelöst durch eine Benutzeraktion:

sequenceDiagram
    actor User
    participant App as ExportDialog
    participant Lib as MediaLibrary
    participant Asset as VideoAsset

    User->>App: click "Export"
    App->>Lib: find_asset("intro.mp4")
    Lib-->>App: asset
    App->>Asset: export("/renders/intro.mp4")
    activate Asset
    Asset-->>App: success
    deactivate Asset
    App-->>User: show confirmation

Das Diagramm entspricht direkt einem Codeablauf: Jeder Pfeil nach rechts ist ein Methodenaufruf, jeder gestrichelte Pfeil ein return. Genau darin liegt der Wert des Sequenzdiagramms: Es macht die Aufrufkette sichtbar, die im Code über mehrere Dateien verteilt ist. Wer einen fremden Ablauf verstehen oder einen eigenen entwerfen will, skizziert die Beteiligten und verfolgt die Nachrichten.

Reale Abläufe enthalten Fallunterscheidungen. Sequenzdiagramme bilden sie mit gerahmten Fragmenten ab: alt für Alternativen (mit Bedingungen in eckigen Klammern), opt für optionale Teile, loop für Wiederholungen:

sequenceDiagram
    actor User
    participant App as ExportDialog
    participant Asset as VideoAsset

    User->>App: click "Export"
    App->>Asset: export("/renders/intro.mp4")
    alt export succeeds
        Asset-->>App: success
        App-->>User: show confirmation
    else disk full
        Asset-->>App: raise ExportError
        App-->>User: show error dialog
    end

Damit lässt sich auch die Fehlerbehandlung aus Kapitel 7 modellieren: Die Exception erscheint als alternative Antwort, und das Diagramm dokumentiert, wo sie behandelt wird (hier im Dialog, nicht im Asset). Eine Warnung aus der Praxis: Sequenzdiagramme mit vielen verschachtelten Fragmenten werden schnell unlesbar. Ein Sequenzdiagramm zeigt idealerweise einen interessanten Durchlauf (den Erfolgsfall oder einen bestimmten Fehlerfall); für die Gesamtheit aller Wege ist das Aktivitätsdiagramm das bessere Werkzeug.

Manche Objekte verhalten sich je nach Vorgeschichte unterschiedlich: Ein Videoplayer reagiert auf die Leertaste mit Pause, wenn er spielt, und mit Wiedergabe, wenn er pausiert ist. Solche Objekte haben einen Zustand, und ihr Verhalten ist erst vollständig beschrieben, wenn alle Zustände und alle Übergänge bekannt sind. Genau das leistet das Zustandsdiagramm. ile: Zustände als abgerundete Rechtecke, Übergänge als Pfeile, beschriftet mit dem auslösenden Ereignis. Ein gefüllter Punkt markiert den Startzustand, ein umrandeter Punkt das Ende.

stateDiagram-v2
    [*] --> Stopped
    Stopped --> Playing : play()
    Playing --> Paused : pause()
    Paused --> Playing : play()
    Playing --> Stopped : stop()
    Paused --> Stopped : stop()
    Playing --> Stopped : end of media
    Stopped --> [*] : close()

Das Diagramm beantwortet Fragen, die im Code verstreut sind: Was passiert bei pause() im Zustand Stopped? (Nichts, es gibt keinen Übergang; der Aufruf wird ignoriert oder abgelehnt.) Kann man von Paused direkt zu Stopped? (Ja.) Diese Vollständigkeit ist die Stärke der Notation: Ein Zustandsdiagramm mit n Zuständen und m Ereignissen zwingt dazu, alle n·m Kombinationen zu bedenken, während im Code vergessene Kombinationen als Fehler enden.

Übergänge können zusätzlich Bedingungen in eckigen Klammern tragen: play() [file loaded] bedeutet, dass der Übergang nur stattfindet, wenn die Bedingung erfüllt ist.

Die direkte Übersetzung eines Zustandsdiagramms ist ein Attribut, das den Zustand hält, und Methoden, die Übergänge prüfen:

class VideoPlayer:
def __init__(self):
self.state = "stopped"
def play(self):
if self.state in ("stopped", "paused"):
self.state = "playing"
def pause(self):
if self.state == "playing":
self.state = "paused"
def stop(self):
if self.state in ("playing", "paused"):
self.state = "stopped"

Jedes if entspricht exakt einer Pfeilmenge des Diagramms; Diagramm und Code lassen sich Zeile für Zeile gegeneinander prüfen. Zustandsbehaftete Objekte sind in der Medientechnik allgegenwärtig: Player, Aufnahmegeräte (bereit/aufnehmend/gesperrt), Render-Jobs (wartend/laufend/fertig/fehlgeschlagen), Netzwerkverbindungen, Benutzeroberflächen mit Modi.

Das Aktivitätsdiagramm beschreibt einen Arbeitsablauf von Anfang bis Ende: Aktionen, Entscheidungen, Wiederholungen und parallele Zweige. Es ähnelt dem klassischen Flussdiagramm, ist aber in der UML genormt und um Konzepte wie Parallelität erweitert. Im Unterschied zum Sequenzdiagramm stehen nicht die beteiligten Objekte im Vordergrund, sondern die Schritte des Ablaufs; im Unterschied zum Zustandsdiagramm beschreibt es einen Prozess mit Anfang und Ende, nicht den Lebenszyklus eines Objekts.

Die Bestandteile: Aktionen als abgerundete Rechtecke, Entscheidungen als Rauten mit beschrifteten Ausgängen, Start- und Endpunkt wie beim Zustandsdiagramm. Ein Balken (Fork/Join) teilt den Ablauf in parallele Zweige und führt sie wieder zusammen.

Als Beispiel die Abgabe eines Videoprojekts, vom Rohschnitt bis zum Upload:

flowchart TD
    start([start]) --> edit[finish the edit]
    edit --> check{quality check passed?}
    check -- no --> fix[apply corrections]
    fix --> check
    check -- yes --> fork[/fork/]
    fork --> render[render video file]
    fork --> thumb[create thumbnail and description]
    render --> join[\join\]
    thumb --> join
    join --> upload[upload to platform]
    upload --> done([end])

Lesart: Nach bestandener Qualitätskontrolle laufen Rendern und die Erstellung der Begleitmaterialien parallel; erst wenn beide fertig sind (Join), beginnt der Upload. Die Schleife über die Qualitätskontrolle zeigt den Korrekturzyklus. Aktivitätsdiagramme eignen sich damit für alles, was Schrittfolgen mit Entscheidungen enthält: Geschäftsprozesse, Bedienabläufe, aber auch die Grobstruktur eines Algorithmus, bevor er implementiert wird.

Die Entscheidungshilfe in Frageform:

  • Geht es um das Zusammenspiel mehrerer Objekte in einem konkreten Fall (“Was passiert genau, wenn der Benutzer auf Export klickt”)? Sequenzdiagramm.
  • Geht es um ein Objekt mit Modi, dessen Reaktionen von der Vorgeschichte abhängen (“In welchen Zuständen kann der Player sein”)? Zustandsdiagramm.
  • Geht es um einen Ablauf mit Entscheidungen und Schritten, unabhängig davon, welche Objekte ihn ausführen (“Wie läuft die Projektabgabe ab”)? Aktivitätsdiagramm.

In einem realen Entwurf ergänzen sich die Sichten: Das Klassendiagramm liefert die Struktur, ein Zustandsdiagramm beschreibt die kritischen zustandsbehafteten Klassen, und Sequenzdiagramme dokumentieren die zwei, drei wichtigsten Durchläufe. Vollständigkeit ist dabei ausdrücklich kein Ziel: Modelliert wird, was komplex, riskant oder erklärungsbedürftig ist. Ein Diagramm, das Triviales abbildet, kostet Pflegeaufwand und beantwortet keine Frage.

Lernergebnisse: Was Sie nach diesem Kapitel können sollten

Abschnitt betitelt „Lernergebnisse: Was Sie nach diesem Kapitel können sollten“

Nach Abschluss dieses Kapitels sollten Schülerinnen und Schüler in der Lage sein:

  • Erklären: den Unterschied zwischen Statik und Dynamik eines Systems sowie die Einsatzgebiete von Sequenz-, Zustands- und Aktivitätsdiagramm erklären.
  • Anwenden: den Ablauf einer gegebenen Problemstellung analysieren und als Sequenzdiagramm mit Beteiligten, Nachrichten und Alternativen darstellen.
  • Anwenden: zustandsbehaftetes Verhalten als Zustandsdiagramm modellieren und in Code mit Zustandsattribut und geprüften Übergängen übersetzen.
  • Anwenden: Arbeitsabläufe mit Entscheidungen, Schleifen und Parallelität als Aktivitätsdiagramm darstellen.
  • Beurteilen: für eine gegebene Fragestellung die passende Diagrammart begründet auswählen.
  • Aufgabe 21 - Modellieren einer Problemstellung (Teil Dynamik)