Kostenlos · Ohne Anmeldung · Für .mmd-Dateien

Mermaid Klassendiagramm Editor

Ein Klassendiagramm zeigt Typen und ihre Beziehungen: was was enthält, was von was erbt, was von was abhängt. Nimm es, wenn die Struktur des Codes der Punkt ist — ein Domänenmodell, eine Schnittstelle, ein Vererbungsbaum. Willst du zeigen, was zur Laufzeit passiert statt wie die Typen zusammenpassen, nimm ein Sequenzdiagramm.

Ein Domänenmodell für Zahlungen

Drei Beziehungsarten in einem Diagramm: Komposition für Teile, die den Besitzer nicht überleben, Vererbung für die Zahlungsarten und eine gewöhnliche Assoziation mit Multiplizität. Die Beziehungspfeile tragen hier fast die ganze Bedeutung — die Klassenkästen sind beinahe nebensächlich.

classDiagram
    class Bestellung {
        +String nummer
        +Status status
        +Betrag summe()
        +void positionHinzufuegen(Artikel a, int menge)
    }
    class Bestellposition {
        +Artikel artikel
        +int menge
        +Betrag zwischensumme()
    }
    class Zahlungsart {
        <<abstract>>
        +autorisieren(Betrag b) bool
    }
    class Kreditkarte {
        +String letzteVier
        +autorisieren(Betrag b) bool
    }
    class Ueberweisung {
        +String iban
        +autorisieren(Betrag b) bool
    }

    Bestellung "1" *-- "1..*" Bestellposition : enthält
    Bestellung --> Zahlungsart : bezahlt mit
    Zahlungsart <|-- Kreditkarte
    Zahlungsart <|-- Ueberweisung
Im Editor öffnen
Werbung

Durchgearbeitete Beispiele

1. Eine Klasse

`+` ist öffentlich, `-` privat, `#` geschützt. Ein Mitglied mit Klammern wird als Methode gezeichnet, ohne Klammern als Feld.

classDiagram
    class Benutzer {
        +String email
        -String passwortHash
        +bool pruefen(String eingabe)
    }
Im Editor öffnen

2. Vererbung und Schnittstellen

`<|--` ist Vererbung, gelesen als „der rechte erweitert den linken". Die `<<interface>>`-Annotation ist eine Beschriftung und kein Verhalten, macht das Diagramm aber erst lesbar.

classDiagram
    class Repository {
        <<interface>>
        +finden(String id) Entitaet
        +speichern(Entitaet e) void
    }
    class PostgresRepository {
        -Verbindung conn
        +finden(String id) Entitaet
        +speichern(Entitaet e) void
    }
    class SpeicherRepository {
        -Map ablage
        +finden(String id) Entitaet
        +speichern(Entitaet e) void
    }
    Repository <|.. PostgresRepository
    Repository <|.. SpeicherRepository
Im Editor öffnen

3. Komposition gegen Aggregation

Der Unterschied ist die Lebensdauer. Eine gefüllte Raute (`*--`) heißt, das Teil stirbt mit dem Ganzen — lösch die Rechnung und ihre Positionen sind weg. Eine hohle Raute (`o--`) heißt, das Teil lebt eigenständig weiter.

classDiagram
    class Rechnung {
        +String nummer
    }
    class Rechnungsposition {
        +String bezeichnung
    }
    class Kunde {
        +String name
    }
    Rechnung "1" *-- "1..*" Rechnungsposition : besteht aus
    Kunde "1" o-- "0..*" Rechnung : hat erhalten
Im Editor öffnen

4. Generics

Tilden liefern Typparameter: `Repository~Benutzer~`. Verschachtelung geht auch, ist gelegentlich nötig und selten eine gute Idee.

classDiagram
    class Repository~T~ {
        +finden(String id) T
        +alle() List~T~
    }
    class Zwischenspeicher~K, V~ {
        +holen(K schluessel) V
        +ablegen(K schluessel, V wert) void
    }
    class BenutzerRepository {
        +findeNachEmail(String email) Benutzer
    }
    Repository~Benutzer~ <|-- BenutzerRepository
Im Editor öffnen

5. Notizen und Richtung

`direction LR` ordnet das Diagramm von links nach rechts an, was einem Vererbungsbaum meist besser bekommt als die Voreinstellung. Eine Notiz ist der richtige Ort für die Einschränkung, die in keinen Klassenkasten passt.

classDiagram
    direction LR
    class Ereignisspeicher {
        +anhaengen(Ereignis e) void
        +abspielen(String stromId) List~Ereignis~
    }
    class Momentaufnahme {
        +int version
        +byte[] inhalt
    }
    Ereignisspeicher --> Momentaufnahme : schreibt alle 100 Ereignisse
    note for Ereignisspeicher "Nur Anfügen. Ereignisse werden nie geändert oder gelöscht."
Im Editor öffnen

Syntaxreferenz für Klassendiagramme

Die Beziehungspfeile sind der Teil, den man sich merken sollte — sie unterscheiden ein Klassendiagramm von einer Kästchen-und-Striche-Zeichnung, und sie lesen sich von rechts nach links, was regelmäßig für Verwirrung sorgt.

SyntaxBedeutung
classDiagramÖffnet das Diagramm. Groß-/Kleinschreibung zählt.
class Name { ... }Klasse mit Mitgliedern. Die schließende Klammer gehört auf eine eigene Zeile.
+mitgliedÖffentlich.
-mitgliedPrivat.
#mitgliedGeschützt.
+methode(Typ arg) RückgabeEine Methode — die Klammern machen sie dazu.
<<interface>> / <<abstract>>Stereotyp, als erste Zeile innerhalb der Klasse geschrieben.
A <|-- BVererbung: B erweitert A.
A <|.. BRealisierung: B implementiert die Schnittstelle A.
A *-- BKomposition: B kann A nicht überleben.
A o-- BAggregation: B existiert auch ohne A.
A --> BGerichtete Assoziation.
A ..> BAbhängigkeit — A benutzt B, hält es aber nicht.
A "1" --> "0..*" B : TextMultiplizität an beiden Enden plus Beschriftung.
class Repo~T~Generischer Typparameter.
note for A "Text"Notiz an einer Klasse.
direction LRLayoutrichtung ändern.
Werbung

Fehler, die Klassendiagramme zerlegen

Nachgestellt mit Mermaid 11.12.2. Klassendiagramme sind nachsichtiger als die meisten Typen hier, deshalb rendern mehrere dieser Fälle anstandslos und liefern das falsche Bild.

Was du siehst

Parse error, endet mit: got 'EOF_IN_STRUCT'

Warum

Ein mit `{` geöffneter Klassenrumpf, der nie geschlossen wurde. Der Tokenname ist ausnahmsweise hilfreich: Die Datei endete, während der Parser noch in einer Klasse war.

Lösung

Die Klammer auf einer eigenen Zeile schließen.

Fehlerhaft
classDiagram
    class Bestellung {
        +String nummer
Korrigiert
classDiagram
    class Bestellung {
        +String nummer
    }

Was du siehst

Parse error, endet mit: got 'ANNOTATION_END'

Warum

Ein Sequenzdiagramm-Pfeil in einem Klassendiagramm. `->>` bedeutet hier nichts, und der Parser kommt weit genug hinein, um einen verwirrenden Tokennamen auszugeben.

Lösung

Eine Klassenbeziehung verwenden: `-->` für Assoziation, `<|--` für Vererbung, `*--` für Komposition.

Fehlerhaft
classDiagram
    Bestellung ->> Kunde
Korrigiert
classDiagram
    Bestellung --> Kunde : gehört zu

Was du siehst

No diagram type detected matching given configuration

Warum

Falsche Groß-/Kleinschreibung. `classdiagram` ist nicht `classDiagram`.

Lösung

Das D großschreiben.

Fehlerhaft
classdiagram
    class Bestellung
Korrigiert
classDiagram
    class Bestellung

Was du siehst

Der Pfeil zeigt in die entgegengesetzte Richtung

Warum

Beziehungspfeile werden von der Pfeilspitze rückwärts gelesen. `A <|-- B` heißt, B erbt von A, nicht umgekehrt. Falsch herum geschrieben rendert es trotzdem — es behauptet nun nur, deine Basisklasse erbe von ihrer eigenen Unterklasse.

Lösung

Lies es als „das ferne Ende erweitert das angespitzte Ende". Die Oberklasse steht links von `<|--`.

Fehlerhaft
classDiagram
    Kreditkarte <|-- Zahlungsart
Korrigiert
classDiagram
    Zahlungsart <|-- Kreditkarte

Was du siehst

Ein Feld erscheint, wo du eine Methode erwartet hast

Warum

Nur die Klammern unterscheiden eine Methode von einem Feld. `+speichern` ist ein Feld namens speichern, `+speichern()` eine Methode. Beides ist gültig, also warnt nichts.

Lösung

Die Klammern ergänzen und dahinter den Rückgabetyp, wenn er sichtbar sein soll.

Fehlerhaft
classDiagram
    class Repo {
        +speichern
        +finden
    }
Korrigiert
classDiagram
    class Repo {
        +speichern(Entitaet e) void
        +finden(String id) Entitaet
    }

Was du siehst

Komposition und Aggregation sehen fast gleich aus und bedeuten das Gegenteil

Warum

`*--` und `o--` unterscheiden sich um ein Zeichen und kodieren einen echten inhaltlichen Unterschied: ob das Teil das Ganze überleben kann. Das falsche zu nehmen ergibt ein formal einwandfreies Diagramm, das über deine Domäne die Unwahrheit sagt.

Lösung

Gefüllte Raute `*--`, wenn das Löschen des Elternobjekts das Kind mitnimmt. Hohle `o--`, wenn nicht.

Fehlerhaft
classDiagram
    Bestellung o-- Bestellposition : enthält
Korrigiert
classDiagram
    Bestellung *-- Bestellposition : enthält

Hinweise zum Rendern

Gemessen an Mermaid 11.12.2, so wie diese Seite es einsetzt.

Klassendiagramme wachsen schneller in die Höhe als jeder andere Typ hier

Drei Klassen ergeben eine viewBox von etwa 94×610. Vierzig Klassen ergeben 108×6900 — rund 172 Pixel Höhe pro Klasse, das steilste Wachstum der sechs Typen auf dieser Seite. Ein Diagramm mit vierzig Klassen ist knapp siebentausend Pixel hoch und als einzelnes Bild unbrauchbar. `direction LR` hilft, aber ab etwa fünfzehn Klassen ist es ehrlicher, das Diagramm nach fachlichen Bereichen zu teilen.

Die Zahl der Mitglieder beeinflusst die Breite kaum

Die Breite bestimmt die längste einzelne Mitgliedssignatur, nicht wie viele Mitglieder es gibt. Eine Klasse mit zwanzig kurzen Feldern ist nicht breiter als eine mit dreien. Du kannst also bei Mitgliedern großzügig und bei Klassen sparsam sein — das Gegenteil dessen, was die meisten zuerst tun.

Beschriftungen sind HTML, deshalb rendert der PNG-Export neu

Klassenbeschriftungen stecken in einem SVG-`<foreignObject>`, das Browser nicht auf ein Canvas zeichnen. Der PNG-Export dieser Seite hat deshalb früher still versagt und eine SVG-Datei zurückgegeben; inzwischen rendert er das Diagramm zuerst mit reinen SVG-Textbeschriftungen neu. Das PNG ist korrekt und in voller Größe, die Typografie weicht minimal vom Bildschirm ab.

Generics verwenden Tilden, und das hat eine Nebenwirkung

`Repository~T~` gibt es, weil spitze Klammern mit dem HTML in Beschriftungen kollidieren würden. Es heißt aber auch, dass eine echte Tilde in einem Klassen- oder Mitgliedsnamen als Beginn eines Typparameters gelesen wird. Selten, aber wenn es passiert, ausgesprochen verwirrend.

Das Theme ändert Farben, niemals das Layout

Helles und dunkles Theme ergeben für dieselbe Quelle eine identische viewBox. Ein Klassenkasten kann beim Themewechsel also weder seine Größe ändern noch Mitglieder abschneiden.

Wann etwas anderes besser passt

Dokumentierst du eine Datenbank statt eines Typsystems, nimm ein ER-Diagramm. Der Unterschied zählt: Klassendiagramme modellieren Verhalten und Vererbung, die Tabellen nicht haben, und ER-Diagramme modellieren Schlüssel und Multiplizität sauber, was Klassendiagramme nur andeuten.

Besteht das Diagramm überwiegend aus Kästen mit `-->` dazwischen und ohne Mitglieder, zeichnest du ein Architekturbild und kein Klassendiagramm. Ein Flussdiagramm mit Subgraphen sieht besser aus und behauptet weniger.

Und wird die Klassenliste aus dem Code erzeugt, überlege, ob das Diagramm es nicht auch sollte. Ein handgepflegtes Klassendiagramm einer Codebasis, die sich wöchentlich ändert, ist binnen eines Monats falsch — und ein falsches Diagramm kostet mehr als gar keines.

Andere Diagrammtypen

Geschrieben von Dominik Malsch · Zuletzt aktualisiert:

Editor öffnen →