Skip to content
IRC-Coding IRC-Coding
UML Class Diagrams Relationships Association Aggregation Composition Dependency Inheritance PlantUML

UML Class Diagrams: Relationships, Association & Composition

Master UML class diagrams with associations, aggregation, composition, dependency, and inheritance. PlantUML examples included.

S

schutzgeist

2 min read

UML Class Diagrams: Relationships, Association, Aggregation & Composition

UML class diagrams are the most important tool for visualizing object-oriented software architectures. Relationships between classes define the structure and behavior of the system.

Basics of UML Class Diagrams

Class Representation

Simple Class with Interface

    @startuml
' Basis-Klasse mit Attributen und Methoden
class Student {
-matrikelNr: int
-name: String
-semester: int
+getName(): String
+setMatrikelNr(nr: int): void
+studieren(): void
}

' Interface mit Methoden
interface Lernbar {
+lernen(): void
+pruefungAblegen(): boolean
}

' Interface
interface Lernfaehig {
+{abstract} lernen(fach: String): void
+{abstract} pruefungAblegen(fach: String): boolean
}

' Student implementiert Lernbar
Student ..|> Lernbar
@enduml
  

Visibility Modifiers

SymbolMeaningDescription
+publicAccessible from anywhere
-privateOnly within the class
#protectedWithin the class and subclasses
~packageOnly within the package

Relationship Types in UML

1. Association

Associations describe structural relationships between classes.

@startuml
class Student {
  -name: String
  +getName(): String
}

class Kurs {
  -titel: String
  -credits: int
  +getTitel(): String
}

' Einfache Assoziation
Student "1" -- "n" Kurs : belegt >

' Assoziation mit Rollen und Attributen
Student "1" -- "*" Note : \
  note : hat
  note : noteWert: double
  note : datum: Date

' Gerichtete Assoziation
Student "1" -> "*" Projekt : leitet >

@enduml

Java Implementation of Associations

public class AssociationExamples {
    
    // Many-to-many association
    public class Student {
        private String name;
        private List<Kurs> belegteKurse = new ArrayList<>();
        private List<Note> noten = new ArrayList<>();
        private List<Projekt> geleiteteProjekte = new ArrayList<>();
        
        public void belegeKurs(Kurs kurs) {
            belegteKurse.add(kurs);
            kurs.addStudent(this);
        }
        
        public void addNote(Note note) {
            noten.add(note);
        }
        
        public void leiteProjekt(Projekt projekt) {
            geleiteteProjekte.add(projekt);
        }
        
        // Getters and setters
        public String getName() { return name; }
        public List<Kurs> getBelegteKurse() { return new ArrayList<>(belegteKurse); }
    }
    
    public class Kurs {
        private String titel;
        private int credits;
        private List<Student> studenten = new ArrayList<>();
        
        public void addStudent(Student student) {
            studenten.add(student);
        }
        
        // Getters and setters
        public String getTitel() { return titel; }
        public List<Student> getStudenten() { return new ArrayList<>(studenten); }
    }
    
    public class Note {
        private double noteWert;
        private Date datum;
        private Student student;
        
        public Note(double noteWert, Date datum, Student student) {
            this.noteWert = noteWert;
            this.datum = datum;
            this.student = student;
            student.addNote(this);
        }
        
        // Getters and setters
        public double getNoteWert() { return noteWert; }
        public Date getDatum() { return datum; }
    }
    
    public class Projekt {
        private String name;
        private Student leiter;
        private List<Student> mitglieder = new ArrayList<>();
        
        public Projekt(String name, Student leiter) {
            this.name = name;
            this.leiter = leiter;
            leiter.leiteProjekt(this);
        }
        
        // Getters and setters
        public String getName() { return name; }
        public Student getLeiter() { return leiter; }
    }
}

2. Aggregation

Aggregation is a special form of association where a part object can exist without the whole.

@startuml
class Abteilung {
  -name: String
  +getName(): String
}

class Mitarbeiter {
  -name: String
  -position: String
  +getName(): String
}

' Aggregation (empty diamond)
Abteilung o-- "*" Mitarbeiter : hat >

class Universitaet {
  -name: String
  +getName(): String
}

class Fakultaet {
  -name: String
  +getName(): String
}

' Aggregation
Universitaet o-- "*" Fakultaet : besitzt >

@enduml

Java Implementation of Aggregation

public class AggregationExamples {
    
    // Department can exist without employees
    public class Abteilung {
        private String name;
        private List<Mitarbeiter> mitarbeiter = new ArrayList<>();
        
        public Abteilung(String name) {
            this.name = name;
        }
        
        public void addMitarbeiter(Mitarbeiter mitarbeiter) {
            this.mitarbeiter.add(mitarbeiter);
        }
        
        public void removeMitarbeiter(Mitarbeiter mitarbeiter) {
            this.mitarbeiter.remove(mitarbeiter);
        }
        
        // Employees can also exist without a department
        public String getName() { return name; }
        public List<Mitarbeiter> getMitarbeiter() { 
            return new ArrayList<>(mitarbeiter); 
        }
    }
    
    public class Mitarbeiter {
        private String name;
        private String position;
        private Abteilung abteilung; // Optional
        
        public Mitarbeiter(String name, String position) {
            this.name = name;
            this.position = position;
        }
        
        public void setAbteilung(Abteilung abteilung) {
            this.abteilung = abteilung;
            if (abteilung != null) {
                abteilung.addMitarbeiter(this);
            }
        }
        
        public void removeAbteilung() {
            if (abteilung != null) {
                abteilung.removeMitarbeiter(this);
                this.abteilung = null;
            }
        }
        
        // Employees exist independently of department
        public String getName() { return name; }
        public Abteilung getAbteilung() { return abteilung; }
    }
}

3. Composition

Composition is a stronger form of aggregation where the part object cannot exist without the whole.

@startuml
class Auto {
  -marke: String
  -modell: String
  +fahren(): void
}

class Motor {
  -leistung: int
  -typ: String
  +starten(): void
}

class Reifen {
  -groesse: int
  -druck: double
  +aufpumpen(): void
}

' Composition (filled diamond)
Auto *-- "1" Motor : hat >
Auto *-- "4" Reifen : hat >

class Haus {
  -adresse: String
  +wohnen(): void
}

class Zimmer {
  -flaeche: double
  -typ: String
  +reinigen(): void
}

' Composition
Haus *-- "*" Zimmer : hat >

@enduml

Java Implementation of Composition

public class CompositionExamples {
    
    // Engine exists only in the car
    public class Auto {
        private String marke;
        private String modell;
        private Motor motor; // Exists only with car
        private List<Reifen> reifen = new ArrayList<>(); // Exist only with car
        
        public Auto(String marke, String modell) {
            this.marke = marke;
            this.modell = modell;
            this.motor = new Motor(200, "Diesel"); // Engine is created in car
            this.reifen.addAll(Arrays.asList(
                new Reifen(205), new Reifen(205), 
                new Reifen(205), new Reifen(205)
            ));
        }
        
        public void fahren() {
            motor.starten();
            System.out.println(marke + " " + modell + " fährt");
        }
        
        // Getters
        public String getMarke() { return marke; }
        public Motor getMotor() { return motor; }
        public List<Reifen> getReifen() { 
            return new ArrayList<>(reifen); 
        }
    }
    
    public class Motor {
        private int leistung;
        private String typ;
        
        // Private constructor - only callable by car
        private Motor(int leistung, String typ) {
            this.leistung = leistung;
            this.typ = typ;
        }
        
        public void starten() {
            System.out.println("Motor (" + typ + ", " + leistung + " PS) gestartet");
        }
        
        // Getters
        public int getLeistung() { return leistung; }
        public String getTyp() { return typ; }
    }
    
    public class Reifen {
        private int groesse;
        private double druck;
        
        // Private constructor
        private Reifen(int groesse) {
            this.groesse = groesse;
            this.druck = 2.5; // Standard pressure
        }
        
        public void aufpumpen(double druck) {
            this.druck = druck;
            System.out.println("Reifen auf " + druck + " bar aufgepumpt");
        }
        
        // Getters
        public int getGroesse() { return groesse; }
        public double getDruck() { return druck; }
    }
}

4. Dependency

Dependencies show usage relationships between classes.

@startuml
class Bestellung {
  -datum: Date
  -gesamtsumme: double
  +berechneGesamtsumme(): double
}

class PreisRechner {
  +berechnePreis(produkte: List<Produkt>): double
  +berechneRabatt(betrag: double, rabatt: double): double
}

' Dependency (dashed line)
Bestellung ..> PreisRechner : uses >

class Logger {
  +logInfo(nachricht: String): void
  +logError(nachricht: String): void
}

class DatenbankService {
  +speichern(daten: Object): void
  +laden(id: String): Object
}

Bestellung ..> Logger : logs >
Bestellung ..> DatenbankService : saves >

@enduml

Java Implementation of Dependencies

public class DependencyExamples {
    
    public class Bestellung {
        private Date datum;
        private List<Produkt> produkte = new ArrayList<>();
        private PreisRechner preisRechner;
        private Logger logger;
        private DatenbankService datenbankService;
        
        public Bestellung(PreisRechner preisRechner, Logger logger, 
                         DatenbankService datenbankService) {
            this.datum = new Date();
            this.preisRechner = preisRechner;
            this.logger = logger;
            this.datenbankService = datenbankService;
        }
        
        public void addProdukt(Produkt produkt) {
            produkte.add(produkt);
            logger.logInfo("Produkt hinzugefügt: " + produkt.getName());
        }
        
        public double berechneGesamtsumme() {
            double summe = preisRechner.berechnePreis(produkte);
            double rabatt = preisRechner.berechneRabatt(summe, 0.1);
            
            logger.logInfo("Gesamtsumme berechnet: " + (summe - rabatt));
            return summe - rabatt;
        }
        
        public void speichern() {
            try {
                datenbankService.speichern(this);
                logger.logInfo("Bestellung gespeichert");
            } catch (Exception e) {
                logger.logError("Fehler beim Speichern: " + e.getMessage());
            }
        }
        
        // Getter
        public Date getDatum() { return datum; }
        public List<Produkt> getProdukte() { return new ArrayList<>(produkte); }
    }
    
    // Dependency classes
    public class PreisRechner {
        public double berechnePreis(List<Produkt> produkte) {
            return produkte.stream()
                .mapToDouble(Produkt::getPreis)
                .sum();
        }
        
        public double berechneRabatt(double betrag, double rabattProzent) {
            return betrag * rabattProzent;
        }
    }
    
    public class Logger {
        public void logInfo(String nachricht) {
            System.out.println("INFO: " + nachricht);
        }
        
        public void logError(String nachricht) {
            System.err.println("ERROR: " + nachricht);
        }
    }
    
    public class DatenbankService {
        public void speichern(Object daten) {
            System.out.println("Daten gespeichert: " + daten);
        }
        
        public Object laden(String id) {
            System.out.println("Daten geladen: " + id);
            return null;
        }
    }
    
    public class Produkt {
        private String name;
        private double preis;
        
        public Produkt(String name, double preis) {
            this.name = name;
            this.preis = preis;
        }
        
        // Getter
        public String getName() { return name; }
        public double getPreis() { return preis; }
    }
}

5. Inheritance

Inheritance shows “is-a” relationships between classes.

@startuml
' Abstract base class
abstract class Fahrzeug {
  #marke: String
  #baujahr: int
  
  +{abstract} fahren(): void
  +{abstract} bremsen(): void
  +getInfo(): String
}

' Concrete subclasses
class Auto extends Fahrzeug {
  -anzahlTueren: int
  +fahren(): void
  +bremsen(): void
  +offnen(): void
}

class Motorrad extends Fahrzeug {
  -typ: String
  +fahren(): void
  +bremsen(): void
  +lenken(): void
}

class Fahrrad extends Fahrzeug {
  -anzahlGaenge: int
  +fahren(): void
  +bremsen(): void
  +schalten(): void
}

@enduml

Java Implementation of Inheritance

public class InheritanceExamples {
    
    // Abstract base class
    public abstract class Fahrzeug {
        protected String marke;
        protected int baujahr;
        
        public Fahrzeug(String marke, int baujahr) {
            this.marke = marke;
            this.baujahr = baujahr;
        }
        
        // Abstract methods
        public abstract void fahren();
        public abstract void bremsen();
        
        // Concrete method
        public String getInfo() {
            return marke + " aus " + baujahr;
        }
        
        // Getter
        public String getMarke() { return marke; }
        public int getBaujahr() { return baujahr; }
    }
    
    // Concrete subclasses
    public class Auto extends Fahrzeug {
        private int anzahlTueren;
        
        public Auto(String marke, int baujahr, int anzahlTueren) {
            super(marke, baujahr);
            this.anzahlTueren = anzahlTueren;
        }
        
        @Override
        public void fahren() {
            System.out.println("Auto " + marke + " fährt mit " + anzahlTueren + " Türen");
        }
        
        @Override
        public void bremsen() {
            System.out.println("Auto bremst mit Bremsscheiben");
        }
        
        public void offnen() {
            System.out.println("Autotür wird geöffnet");
        }
        
        @Override
        public String getInfo() {
            return super.getInfo() + " (Auto, " + anzahlTueren + " Türen)";
        }
    }
    
    public class Motorrad extends Fahrzeug {
        private String typ;
        
        public Motorrad(String marke, int baujahr, String typ) {
            super(marke, baujahr);
            this.typ = typ;
        }
        
        @Override
        public void fahren() {
            System.out.println("Motorrad " + marke + " (" + typ + ") fährt");
        }
        
        @Override
        public void bremsen() {
            System.out.println("Motorrad bremst mit Scheibenbremsen");
        }
        
        public void lenken() {
            System.out.println("Motorrad wird gelenkt");
        }
        
        @Override
        public String getInfo() {
            return super.getInfo() + " (Motorrad, " + typ + ")";
        }
    }
    
    public class Fahrrad extends Fahrzeug {
        private int anzahlGaenge;
        
        public Fahrrad(String marke, int baujahr, int anzahlGaenge) {
            super(marke, baujahr);
            this.anzahlGaenge = anzahlGaenge;
        }
        
        @Override
        public void fahren() {
            System.out.println("Fahrrad " + marke + " wird in die Pedale getreten");
        }
        
        @Override
        public void bremsen() {
            System.out.println("Fahrrad bremst mit Felgenbremsen");
        }
        
        public void schalten() {
            System.out.println("Fahrrad schaltet Gang");
        }
        
        @Override
        public String getInfo() {
            return super.getInfo() + " (Fahrrad, " + anzahlGaenge + " Gänge)";
        }
    }
}

6. Implementation

Implementation shows the relationship between interfaces and implementing classes.

@startuml
' Interfaces
interface Fliegend {
  +{abstract} fliegen(): void
  +{abstract} landen(): void
}

interface Schwimmend {
  +{abstract} schwimmen(): void
  +{abstract} tauchen(): void
}

' Klasse implementiert ein Interface
class Vogel implements Fliegend {
  -art: String
  +fliegen(): void
  +landen(): void
}

' Klasse implementiert mehrere Interfaces
class Ente implements Fliegend, Schwimmend {
  -rasse: String
  +fliegen(): void
  +landen(): void
  +schwimmen(): void
  +tauchen(): void
}

' Abstrakte Klasse implementiert Interface
abstract class Wasserlebewesen implements Schwimmend {
  -lebensraum: String
  +{abstract} atmen(): void
  +schwimmen(): void
  +tauchen(): void
}

class Fisch extends Wasserlebewesen {
  -art: String
  +atmen(): void
}

@enduml

Java Implementation of Interfaces

public class InterfaceExamples {
    
    // Interfaces
    public interface Fliegend {
        void fliegen();
        void landen();
    }
    
    public interface Schwimmend {
        void schwimmen();
        void tauchen();
    }
    
    // Simple implementation
    public class Vogel implements Fliegend {
        private String art;
        
        public Vogel(String art) {
            this.art = art;
        }
        
        @Override
        public void fliegen() {
            System.out.println(art + " fliegt in die Luft");
        }
        
        @Override
        public void landen() {
            System.out.println(art + " landet sanft");
        }
        
        public String getArt() { return art; }
    }
    
    // Implementing multiple interfaces
    public class Ente implements Fliegend, Schwimmend {
        private String rasse;
        
        public Ente(String rasse) {
            this.rasse = rasse;
        }
        
        @Override
        public void fliegen() {
            System.out.println(rasse + " fliegt in Formation");
        }
        
        @Override
        public void landen() {
            System.out.println(rasse + " landet auf dem Wasser");
        }
        
        @Override
        public void schwimmen() {
            System.out.println(rasse + " schwimmt elegant");
        }
        
        @Override
        public void tauchen() {
            System.out.println(rasse + " taucht nach Fischen");
        }
        
        public String getRasse() { return rasse; }
    }
    
    // Abstract class with interface
    public abstract class Wasserlebewesen implements Schwimmend {
        protected String lebensraum;
        
        public Wasserlebewesen(String lebensraum) {
            this.lebensraum = lebensraum;
        }
        
        public abstract void atmen();
        
        @Override
        public void schwimmen() {
            System.out.println("Schwimmt im " + lebensraum);
        }
        
        @Override
        public void tauchen() {
            System.out.println("Taucht tief im " + lebensraum);
        }
        
        public String getLebensraum() { return lebensraum; }
    }
    
    // Concrete subclass
    public class Fisch extends Wasserlebewesen {
        private String art;
        
        public Fisch(String art, String lebensraum) {
            super(lebensraum);
            this.art = art;
        }
        
        @Override
        public void atmen() {
            System.out.println(art + " atmet mit Kiemen im Wasser");
        }
        
        public String getArt() { return art; }
    }
}

Complex Class Diagrams

Complete Example: University System

@startuml
' Abstract base classes
abstract class Person {
  #name: String
  #alter: int
  +{abstract} getInfo(): String
  +geburtstagFeiern(): void
}

abstract class Mitarbeiter extends Person {
  #mitarbeiterNr: String
  #gehalt: double
  +{abstract} arbeiten(): void
  +gehaltErhoehen(prozent: double): void
}

' Concrete classes
class Student extends Person {
  -matrikelNr: String
  -fach: String
  +studieren(): void
  +pruefungAblegen(): boolean
  +getInfo(): String
}

class Dozent extends Mitarbeiter {
  -fachbereich: String
  +arbeiten(): void
  +vorlesungHalten(): void
  +klausurKorrigieren(): void
  +getInfo(): String
}

class Verwaltungsmitarbeiter extends Mitarbeiter {
  -abteilung: String
  +arbeiten(): void
  +dokumenteVerwalten(): void
  +getInfo(): String
}

' Additional classes
class Kurs {
  -titel: String
  -credits: int
  -dozent: Dozent
  +getTitel(): String
  +setDozent(dozent: Dozent): void
}

class Pruefung {
  -datum: Date
  -note: double
  -student: Student
  -kurs: Kurs
  +noteEintragen(note: double): void
  +bestanden(): boolean
}

class Raum {
  -nummer: String
  -kapazitaet: int
  +gebucht(): boolean
  +reservieren(): void
}

' Relationships
Person <|-- Student
Person <|-- Mitarbeiter
Mitarbeiter <|-- Dozent
Mitarbeiter <|-- Verwaltungsmitarbeiter

Dozent "1" -- "*" Kurs : unterrichtet >
Student "n" -- "n" Kurs : belegt >
Student "n" -- "n" Pruefung : schreibt >
Kurs "1" -- "n" Pruefung : hat >
Kurs "n" -- "1" Raum : findetStattIn >

' Aggregation
Fakultaet o-- "*" Dozent : beschaeftigt >
Fakultaet o-- "*" Student : immatrikuliert >

' Composition
Universitaet *-- "*" Fakultaet : besitzt >

@enduml

Java Implementation of the University System

public class UniversitySystem {
    
    // Abstract base class
    public abstract class Person {
        protected String name;
        protected int alter;
        
        public Person(String name, int alter) {
            this.name = name;
            this.alter = alter;
        }
        
        public abstract String getInfo();
        
        public void geburtstagFeiern() {
            alter++;
            System.out.println("Herzlichen Glückwunsch zum " + alter + ". Geburtstag, " + name + "!");
        }
        
        // Getter
        public String getName() { return name; }
        public int getAlter() { return alter; }
    }
    
    // Abstract employee class
    public abstract class Mitarbeiter extends Person {
        protected String mitarbeiterNr;
        protected double gehalt;
        
        public Mitarbeiter(String name, int alter, String mitarbeiterNr, double gehalt) {
            super(name, alter);
            this.mitarbeiterNr = mitarbeiterNr;
            this.gehalt = gehalt;
        }
        
        public abstract void arbeiten();
        
        public void gehaltErhoehen(double prozent) {
            gehalt = gehalt * (1 + prozent / 100);
            System.out.println("Gehalt erhöht auf: " + gehalt);
        }
        
        // Getter
        public String getMitarbeiterNr() { return mitarbeiterNr; }
        public double getGehalt() { return gehalt; }
    }
    
    // Concrete classes
    public class Student extends Person {
        private String matrikelNr;
        private String fach;
        private List<Kurs> belegteKurse = new ArrayList<>();
        private List<Pruefung> pruefungen = new ArrayList<>();
        
        public Student(String name, int alter, String matrikelNr, String fach) {
            super(name, alter);
            this.matrikelNr = matrikelNr;
            this.fach = fach;
        }
        
        @Override
        public String getInfo() {
            return "Student: " + name + " (" + matrikelNr + "), Fach: " + fach;
        }
        
        public void studieren() {
            System.out.println(name + " studiert " + fach);
        }
        
        public boolean pruefungAblegen() {
            return belegteKurse.stream().anyMatch(kurs -> 
                pruefungen.stream()
                    .anyMatch(pruefung -> 
                        pruefung.getKurs().equals(kurs) && pruefung.bestanden()
                    )
            );
        }
        
        public void belegeKurs(Kurs kurs) {
            belegteKurse.add(kurs);
            kurs.addStudent(this);
        }
        
        public void addPruefung(Pruefung pruefung) {
            pruefungen.add(pruefung);
        }
        
        // Getter
        public String getMatrikelNr() { return matrikelNr; }
        public String getFach() { return fach; }
        public List<Kurs> getBelegteKurse() { return new ArrayList<>(belegteKurse); }
    }
    
    public class Dozent extends Mitarbeiter {
        private String fachbereich;
        private List<Kurs> unterrichteteKurse = new ArrayList<>();
        
        public Dozent(String name, int alter, String mitarbeiterNr, double gehalt, String fachbereich) {
            super(name, alter, mitarbeiterNr, gehalt);
            this.fachbereich = fachbereich;
        }
        
        @Override
        public String getInfo() {
            return "Dozent: " + name + " (" + mitarbeiterNr + "), Fachbereich: " + fachbereich;
        }
        
        @Override
        public void arbeiten() {
            System.out.println(name + " arbeitet im Fachbereich " + fachbereich);
        }
        
        public void vorlesungHalten(Kurs kurs) {
            unterrichteteKurse.add(kurs);
            kurs.setDozent(this);
            System.out.println(name + " hält Vorlesung: " + kurs.getTitel());
        }
        
        public void klausurKorrigieren(Pruefung pruefung) {
            System.out.println(name + " korrigiert Klausur für " + pruefung.getStudent().getName());
            pruefung.noteEintragen(Math.random() * 4 + 1); // Random grade 1-5
        }
        
        // Getter
        public String getFachbereich() { return fachbereich; }
        public List<Kurs> getUnterrichteteKurse() { return new ArrayList<>(unterrichteteKurse); }
    }
    
    public class Verwaltungsmitarbeiter extends Mitarbeiter {
        private String abteilung;
        
        public Verwaltungsmitarbeiter(String name, int alter, String mitarbeiterNr, double gehalt, String abteilung) {
            super(name, alter, mitarbeiterNr, gehalt);
            this.abteilung = abteilung;
        }
        
        @Override
        public String getInfo() {
            return "Verwaltungsmitarbeiter: " + name + " (" + mitarbeiterNr + "), Abteilung: " + abteilung;
        }
        
        @Override
        public void arbeiten() {
            System.out.println(name + " arbeitet in der Verwaltung: " + abteilung);
        }
        
        public void dokumenteVerwalten() {
            System.out.println(name + " verwaltet Dokumente in " + abteilung);
        }
        
        // Getter
        public String getAbteilung() { return abteilung; }
    }
    
    // Additional classes
    public class Kurs {
        private String titel;
        private int credits;
        private Dozent dozent;
        private List<Student> studenten = new ArrayList<>();
        private List<Pruefung> pruefungen = new ArrayList<>();
        
        public Kurs(String titel, int credits) {
            this.titel = titel;
            this.credits = credits;
        }
        
        public void addStudent(Student student) {
            studenten.add(student);
        }
        
        public void setDozent(Dozent dozent) {
            this.dozent = dozent;
        }
        
        public void addPruefung(Pruefung pruefung) {
            pruefungen.add(pruefung);
        }
        
        // Getter
        public String getTitel() { return titel; }
        public int getCredits() { return credits; }
        public Dozent getDozent() { return dozent; }
        public List<Student> getStudenten() { return new ArrayList<>(studenten); }
    }
    
    public class Pruefung {
        private Date datum;
        private double note;
        private Student student;
        private Kurs kurs;
        
        public Pruefung(Student student, Kurs kurs) {
            this.student = student;
            this.kurs = kurs;
            this.datum = new Date();
            this.note = 0.0; // Not yet graded
        }
        
        public void noteEintragen(double note) {
            this.note = note;
            student.addPruefung(this);
            kurs.addPruefung(this);
        }
        
        public boolean bestanden() {
            return note > 0 && note <= 4.0;
        }
        
        // Getter
        public Date getDatum() { return datum; }
        public double getNote() { return note; }
        public Student getStudent() { return student; }
        public Kurs getKurs() { return kurs; }
    }
    
    public class Raum {
        private String nummer;
        private int kapazitaet;
        private boolean gebucht = false;
        
        public Raum(String nummer, int kapazitaet) {
            this.nummer = nummer;
            this.kapazitaet = kapazitaet;
        }
        
        public void reservieren() {
            gebucht = true;
            System.out.println("Raum " + nummer + " reserviert");
        }
        
        public boolean istGebucht() {
            return gebucht;
        }
        
        // Getter
        public String getNummer() { return nummer; }
        public int getKapazitaet() { return kapazitaet; }
    }
}

Best Practices for UML Class Diagrams

1. Consistent Naming Conventions

// Gute Namenskonventionen
public class NamingConventions {
    
    // Klassen: Substantive, PascalCase
    public class StudentManagementSystem {}
    
    // Methoden: Verben, camelCase
    public void calculateGrade() {}
    public void validateInput() {}
    
    // Variablen: camelCase, beschreibend
    private List<Student> enrolledStudents;
    private double averageGrade;
    
    // Konstanten: UPPER_CASE
    public static final int MAX_STUDENTS_PER_COURSE = 100;
    
    // Interfaces: Adjektive oder Fähigkeiten, PascalCase
    public interface Printable {}
    public interface Serializable {}
    public interface StudentRepository {}
}

2. Separating Responsibilities

@startuml
' Gute Aufteilung nach Verantwortlichkeiten
class UserRepository {
  +save(user: User): void
  +findById(id: String): User
  +findAll(): List<User>
  +delete(id: String): void
}

class UserService {
  -userRepository: UserRepository
  -emailService: EmailService
  +registerUser(userData: UserData): User
  +authenticateUser(username: String, password: String): boolean
  +updateUserProfile(userId: String, profile: UserProfile): void
}

class EmailService {
  +sendWelcomeEmail(user: User): void
  +sendPasswordReset(user: User): void
}

' Klare Abhängigkeiten
UserService ..> UserRepository : verwendet >
UserService ..> EmailService : verwendet >

@enduml

3. Avoiding Circular Dependencies

@startuml
' Schlecht: Zyklische Abhängigkeiten
class A {
  -b: B
  +doSomething(): void
}

class B {
  -c: C
  +doSomethingElse(): void
}

class C {
  -a: A
  +doAnotherThing(): void
}

A --> B
B --> C
C --> A ' Zyklus!

' Gut: Keine Zyklen
class GoodA {
  -service: CommonService
  +doSomething(): void
}

class GoodB {
  -service: CommonService
  +doSomethingElse(): void
}

class GoodC {
  -service: CommonService
  +doAnotherThing(): void
}

class CommonService {
  +sharedOperation(): void
}

GoodA --> CommonService
GoodB --> CommonService
GoodC --> CommonService

@enduml

Exam-Relevant Concepts

Important Relationship Types

| Relationship Type | Symbol | Meaning | Lifespan |
|---------------|--------|-----------|-------------|
| Association | ---- | Structural relationship | Independent |
| Aggregation | o-- | "has-a" (partial) | Independent |
| Composition | *-- | "has-a" (whole) | Dependent |
| Dependency | ..> | "uses" | Temporary |
| Inheritance | <\|-- | "is-a" | Permanent |
| Implementation | ..\|> | "implements" | Permanent |

Typical Exam Tasks

  1. Draw class diagrams for given scenarios
  2. Identify relationship types
  3. Implement relationships in Java
  4. Refactor poor designs
  5. Explain differences between aggregation and composition

Summary

UML class diagrams are essential for software architecture:

  • Association: Structural relationships between classes
  • Aggregation: “has-a” relationship, parts can exist independently
  • Composition: “has-a” relationship, parts are dependent
  • Dependency: Use of classes or interfaces
  • Inheritance: “is-a” relationship between classes
  • Implementation: Interface realization

Good class design follows SOLID principles and avoids circular dependencies.

Back to Blog
Share:

Related Posts