Die meisten UML-Diagrammtypen leben in Lehrbüchern. Das Klassendiagramm ist das, was Entwickler noch zeichnen: ein Bild der Dinge, um die es in einem System geht, was jedes davon hält, was es kann und wie sie zusammenhängen. Gut gezeichnet beendet es Diskussionen über das Domänenmodell, bevor jemand eine Migration oder eine API schreibt.
Dieser Beitrag baut ein UML-Klassendiagramm für eine kleine Online-Kursplattform auf, eine Entscheidung nach der anderen, und erklärt die Notation, sobald sie auftaucht: Sichtbarkeit, Multiplizität, Assoziation, Komposition, Vererbung und Schnittstellen. Am Ende stehen die Fehler, die Klassendiagramme nutzlos machen, und ein kurzer Blick darauf, wie das Diagramm auf Code abbildet.
Wann ein Klassendiagramm das richtige Bild ist
Die UML-2.5.1-Spezifikation teilt ihre Diagramme in Struktur- und Verhaltensdiagramme. Ein Klassendiagramm ist ein Strukturdiagramm: Es zeigt Typen, ihre Attribute und Operationen und die Beziehungen zwischen ihnen, ohne jeden Zeitbegriff.
| Frage, die du beantworten musst | Diagramm |
|---|---|
| Welche Konzepte es gibt, was sie wissen, wie sie zusammenhängen | Klassendiagramm |
| Wie die Daten gespeichert werden: Tabellen, Schlüssel, Fremdschlüssel | ER-Diagramm |
| Was in welcher Reihenfolge zwischen Beteiligten passiert | Sequenzdiagramm |
| Welche Zustände ein Objekt durchläuft | Zustandsdiagramm |
Ein Klassendiagramm lohnt sich für ein Domänenmodell, für die öffentlichen Typen einer Bibliothek oder für einen Entwurf, den du gleich umsetzen willst. Als Auszug aller Klassen eines Repositorys lohnt es sich nicht: Das zeigt eine IDE besser, und das Bild ist nach dem nächsten Commit veraltet.
Die Notation in zwei Tabellen
Eine Klasse ist ein Kasten mit bis zu drei Abschnitten: Name, Attribute und Operationen. Jeder Abschnitt darf fehlen.
| Element | Notation | Bedeutung |
|---|---|---|
| Abstrakte Klasse | Name kursiv oder {abstract} |
Nicht instanziierbar; Unterklassen vervollständigen sie |
| Schnittstelle | «interface» über dem Namen |
Ein Vertrag aus Operationen |
| Sichtbarkeit | + public, - private, # protected, ~ package |
Wer das Merkmal nutzen darf |
| Attribut | name: Type [multiplicity] = default |
Daten, die das Objekt hält |
| Operation | name(param: Type): ReturnType |
Verhalten, das das Objekt anbietet |
| Statisches Merkmal | Unterstrichen | Gehört zur Klasse, nicht zu einer Instanz |
Beziehungen sind Linien zwischen Klassen, und die Enden tragen den größten Teil der Bedeutung:
| Beziehung | Linie | Lies sie als |
|---|---|---|
| Assoziation | Durchgezogene Linie; eine offene Pfeilspitze markiert ein navigierbares Ende | „steht in Beziehung zu“ |
| Aggregation | Durchgezogene Linie, hohle Raute am Ganzen | „gruppiert“; die Teile existieren eigenständig |
| Komposition | Durchgezogene Linie, gefüllte Raute am Ganzen | „besteht aus“; die Teile gehen mit dem Ganzen |
| Generalisierung | Durchgezogene Linie, hohles Dreieck an der Oberklasse | „ist eine Art von“ |
| Realisierung | Gestrichelte Linie, hohles Dreieck an der Schnittstelle | „implementiert“ |
| Abhängigkeit | Gestrichelte Linie, offene Pfeilspitze am Ziel | „benutzt“; eine Änderung am Ziel kann die Quelle brechen |
Die Komposition ist die strenge Variante. Laut Spezifikation gehört ein Teilobjekt zu jedem Zeitpunkt höchstens einem Kompositum, und wird das Kompositum gelöscht, werden seine Teile mitgelöscht. Die geteilte Aggregation, die hohle Raute, ist die vage Variante: Die Spezifikation sagt selbst, dass ihre genaue Semantik je nach Anwendungsgebiet und Modellierer variiert. Nutze sie nur, wenn dein Team sich einig ist, was sie bedeutet; eine einfache Assoziation sagt dasselbe mit weniger Diskussion.
Multiplizität
Die Multiplizität sagt, wie viele Objekte an einem Ende einer Assoziation stehen können: 1 für genau eines, 0..1 für optional, * (dasselbe wie 0..*) für beliebig viele, 1..* für mindestens eines und Bereiche wie 2..5. Schreib sie an das Ende neben der Klasse, die sie zählt. Lies Course 1 — 1..* Module als: „Ein Kurs hat ein oder mehrere Module, und jedes Modul gehört zu genau einem Kurs.“
Fehlende Multiplizitäten sind der häufigste Grund, warum ein Klassendiagramm Diskussionen auslöst, statt sie zu beenden. Im Beispiel unten sind bei jeder Assoziation beide Enden ausgefüllt.
Das Beispiel: eine Online-Kursplattform
Beginne mit einfachen Sätzen, nicht mit Kästen:
- Dozenten veröffentlichen Kurse. Ein Kurs hat einen oder mehrere Dozenten.
- Ein Kurs besteht aus geordneten Modulen, ein Modul aus geordneten Lektionen.
- Eine Lektion ist ein Video, ein Quiz oder eine Aufgabe.
- Quizze und Aufgaben werden bewertet, Videos nicht.
- Lernende schreiben sich in Kurse ein. Eine Einschreibung verfolgt den Fortschritt und hält die Abgaben der Lernenden.
- Wer einen Kurs abschließt, bekommt für diese Einschreibung ein Zertifikat.
- Kurse sind in Kategorien gruppiert, und ein Kurs kann in mehreren stehen.
Nutzer: eine Klasse, zwei Rollen
Der erste Impuls sind Student und Instructor als Unterklassen von User. Das bricht, sobald ein Dozent den Kurs eines anderen belegt: In den meisten Programmiersprachen hat ein Objekt sein ganzes Leben lang eine Klasse, kann also nicht beides sein und später nicht wechseln. Modelliere Rollen stattdessen als Assoziationen: Ein User lehrt Kurse, und ein User hat Einschreibungen. Heb dir die Vererbung für Dinge auf, die ihr ganzes Leben lang eine Art von etwas sind, etwa ein Quiz als eine Art von Lektion.
Komposition, wo Lebenszyklen verbunden sind
Ein Modul bedeutet außerhalb seines Kurses nichts, eine Lektion außerhalb ihres Moduls ebenso wenig. Wird ein Kurs gelöscht, verschwinden beide. Das ist Komposition: eine gefüllte Raute an Course und an Module, mit 1 am Ganzen. Kategorien sind anders. Das Löschen der Kategorie „Data Engineering“ darf ihre Kurse nicht löschen, also ist Category zu Course eine Aggregation mit * an beiden Enden.
Vererbung plus Schnittstelle
Lesson ist abstrakt; VideoLesson, Quiz und Assignment erben Titel und Position. Die Bewertung schneidet quer durch diesen Baum: Quizze und Aufgaben werden bewertet, Videos nicht, und ein Peer-Review, das nächstes Jahr dazukommt, könnte bewertet werden, ohne überhaupt eine Lektion zu sein. Das ist eine Schnittstelle, Gradable, realisiert von Quiz und Assignment. GradingService hängt von Gradable ab, nicht von den konkreten Klassen, und der gestrichelte Abhängigkeitspfeil sagt genau das.
Eine Assoziation mit eigenen Daten
Enrollment steht zwischen User und Course. UML hat dafür eine eigene Notation, die Assoziationsklasse, die über eine gestrichelte Linie an der Beziehung hängt. Die meisten Teams zeichnen sie stattdessen als normale Klasse mit zwei Assoziationen, weil sie eine eigene Identität, eigene Daten und eigenes Verhalten hat: Einschreibedatum, Fortschritt, Abgaben und höchstens ein Zertifikat.
Diagramminhalt
- Category
- Course
- User
- Module
- Enrollment
- Certificate
- Lesson
- Submission
- VideoLesson
- Quiz
- Assignment
- Gradable
- GradingService
- groups
- teaches
- enrolls
- for
- earns
- holds
- answers
- «use»
So liest du es:
- Oben links, der Katalog.
Coursebesteht ausModule, das ausLessonbesteht, mit gefüllten Rauten am Ganzen.Categorygruppiert Kurse mit einer hohlen Raute. - Unten links, die Lektionstypen.
Lessonist abstrakt.VideoLesson,QuizundAssignmentzeigen mit hohlen Dreiecken darauf. - Rechts, das Lernen. Ein
Userlehrt Kurse, mit1..*Dozenten pro Kurs, und hat beliebig viele Einschreibungen für jeweils genau einen Kurs. EinEnrollmenthält Abgaben und bringt höchstens einCertificateein. - Unten rechts, die Bewertung.
QuizundAssignmentrealisierenGradablemit gestrichelten Linien und hohlen Dreiecken. JedeSubmissionbeantwortet ein bewertbares Element, undGradingServicehängt nur von der Schnittstelle ab.
Häufige Fehler
- Jede Klasse der Codebasis. Zehn bis fünfzehn Klassen pro Diagramm sind eine gute Grenze. Teile ein größeres Modell nach Bereichen auf oder zeig den Rest als Namen ohne Abschnitte.
- Getter und Setter als Operationen. Führe Operationen mit fachlicher Bedeutung auf, etwa
publish()oderenroll(), keine Zugriffsmethoden. - Tabellen als Klassen gezeichnet. Attribute wie
courseIdgehören ins ER-Diagramm. Im Klassendiagramm ist die Assoziationslinie die Referenz. - Vererbung für Rollen. Wenn ein Objekt die Rolle bekommen oder verlieren kann, ist es eine Assoziation, keine Unterklasse.
- Rauten ohne Bedeutung. Wenn niemand sagen kann, was das Löschen des Ganzen mit den Teilen macht, nimm eine einfache Assoziation.
- Implementierungsdetails auf Domänenebene. Lass Framework-Annotationen, DTOs und Repositories weg, es sei denn, das Diagramm handelt von ihnen.
Vom Diagramm zum Code
Das Diagramm bildet direkt auf Code ab. In TypeScript:
interface Gradable {
maxScore(): number;
autoGrade(submission: Submission): Score | null;
}
abstract class Lesson {
constructor(public title: string, public position: number) {}
}
class Quiz extends Lesson implements Gradable {
questions: Question[] = [];
maxScore(): number {
return this.questions.length;
}
autoGrade(submission: Submission): Score | null {
return submission.scoreAgainst(this.questions);
}
}
class Course {
private readonly modules: Module[] = []; // composition: owned and removed with the course
categories: Category[] = []; // aggregation: categories exist on their own
addModule(title: string): Module {
const created = new Module(title, this.modules.length);
this.modules.push(created);
return created;
}
}
Aus Komposition wird Besitz: Der Kurs erzeugt seine Module, und nichts hält eines am Leben, wenn der Kurs weg ist. Aus Aggregation wird eine Referenz auf ein Objekt mit eigenem Lebenszyklus. Wenn Code und Diagramm nicht übereinstimmen, aktualisiere das Diagramm im selben Pull Request; das ist viel einfacher, wenn das Diagramm ein Link statt eines Screenshots ist, wie in Architekturdiagramme, die nicht veralten beschrieben.
In Archboard nachbauen
- Melde dich mit Google oder GitHub an und leg ein Diagramm an.
- Füge aus dem UML-Pack für jedes Konzept eine Klasse hinzu und schreib Attribute und Operationen jeweils in eine eigene Zeile. Setz das Stereotyp von
Lessonaufabstract. - Füge für
Gradableeine Schnittstelle mit ihren zwei Operationen hinzu. - Verbinde die Klassen. Setz das Pfeilende am Ganzen für Komposition auf Gefüllte Raute und für Aggregation auf Raute, und für Vererbung an der Oberklasse auf Dreieck. Zeichne Realisierung als gestrichelte Linie mit einem Dreieck an der Schnittstelle und Abhängigkeit als gestrichelte Linie mit einem Offener Pfeil.
- Schreib die Multiplizitäten als Text neben jedes Ende und benenne Assoziationen wie „teaches“ in der Kantenbeschriftung.
- Füge eine UML-Notiz für Entscheidungen hinzu, etwa warum Rollen Assoziationen sind.
Das Beispiel nutzt 13 Diagramm-Nodes und bleibt damit im Free-Plan. Mit einem über MCP verbundenen KI-Agenten kannst du die Anforderungen beschreiben und ihn die Klassen entwerfen lassen; die Multiplizitäten korrigierst du dann selbst.
FAQ
Was ist der Unterschied zwischen einem Klassendiagramm und einem Objektdiagramm? Ein Klassendiagramm zeigt Typen und die Regeln zwischen ihnen. Ein Objektdiagramm zeigt konkrete Instanzen zu einem Zeitpunkt, mit ihren Werten und Verknüpfungen, und eignet sich, um ein Klassendiagramm an einem echten Beispiel zu prüfen.
Was ist der Unterschied zwischen Aggregation und Komposition? Bei der Komposition gehört ein Teil zu genau einem Ganzen und wird mit ihm gelöscht. Bei der Aggregation können die Teile eigenständig existieren und geteilt werden; ihre genaue Bedeutung bleibt dem Modellierer überlassen, deshalb nutzen viele Teams stattdessen eine einfache Assoziation.
Muss ein Klassendiagramm genau dem Code entsprechen? Ein Domänenmodell sollte den Konzepten und Beziehungen entsprechen, nicht jedem Feld und jeder Methode. Halte es auf einer Ebene, die eine Produktmanagerin und ein Entwickler gleichermaßen lesen können.
Wie unterscheidet sich ein Klassendiagramm von einem C4-Komponentendiagramm? Ein C4-Komponentendiagramm zeigt deploybare Bausteine und ihre Verantwortlichkeiten. Ein Klassendiagramm geht eine Ebene tiefer, zu den Typen darin; siehe das C4-Modell-Diagrammbeispiel.
Kann ich ein Klassendiagramm automatisch aus Code erzeugen? Viele IDEs können das, aber das Ergebnis zeigt jede Klasse und ist schwer zu lesen. Zeichne das Domänenmodell von Hand oder mit einem KI-Agenten und beschränke es auf die Klassen, die zählen.