Skip to content
IRC-Coding IRC-Coding
UML Klassendiagramme Beziehungen Association Aggregation Komposition Dependency Inheritance PlantUML

UML Klassendiagramme: Beziehungen, Association, Aggregation & Komposition

UML Klassendiagramme mit Beziehungen, Association, Aggregation, Komposition, Dependency und Inheritance. PlantUML Beispiele.

S

schutzgeist

1 min read

UML Klassendiagramme: Beziehungen, Association, Aggregation & Komposition

UML Klassendiagramme sind das wichtigste Werkzeug zur Visualisierung von objektorientierten Softwarearchitekturen. Beziehungen zwischen Klassen definieren die Struktur und das Verhalten des Systems.

Grundlagen der UML-Klassendiagramme

Klassendarstellung

Einfache Klasse mit 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
  

Sichtbarkeitsmodifizierer

SymbolBedeutungBeschreibung
+publicVon überall zugreifbar
-privateNur innerhalb der Klasse
#protectedInnerhalb der Klasse und Unterklassen
~packageNur innerhalb des Pakets

Beziehungsarten in UML

1. Assoziation (Association)

Assoziationen beschreiben strukturelle Beziehungen zwischen Klassen.

@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-Implementierung von Assoziationen

public class AssociationExamples {
    
    // Viele-zu-viele Assoziation
    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);
        }
        
        // Getter und Setter
        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);
        }
        
        // Getter und Setter
        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);
        }
        
        // Getter und Setter
        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);
        }
        
        // Getter und Setter
        public String getName() { return name; }
        public Student getLeiter() { return leiter; }
    }
}

2. Aggregation

Aggregation ist eine spezielle Form der Assoziation, bei der ein Teil-Objekt auch ohne das Ganze existieren kann.

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

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

' Aggregation (leere Raute)
Abteilung o-- "*" Mitarbeiter : hat >

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

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

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

@enduml

Java-Implementierung von Aggregation

public class AggregationExamples {
    
    // Abteilung kann ohne Mitarbeiter existieren
    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);
        }
        
        // Mitarbeiter können auch ohne Abteilung existieren
        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;
            }
        }
        
        // Mitarbeiter existieren unabhängig von Abteilung
        public String getName() { return name; }
        public Abteilung getAbteilung() { return abteilung; }
    }
}

3. Komposition (Composition)

Komposition ist eine stärkere Form der Aggregation, bei der das Teil-Objekt ohne das Ganze nicht existieren kann.

@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
}

' Komposition (gefüllte Raute)
Auto *-- "1" Motor : hat >
Auto *-- "4" Reifen : hat >

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

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

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

@enduml

Java-Implementierung von Komposition

public class CompositionExamples {
    
    // Motor existiert nur im Auto
    public class Auto {
        private String marke;
        private String modell;
        private Motor motor; // Existiert nur mit Auto
        private List<Reifen> reifen = new ArrayList<>(); // Existieren nur mit Auto
        
        public Auto(String marke, String modell) {
            this.marke = marke;
            this.modell = modell;
            this.motor = new Motor(200, "Diesel"); // Motor wird im Auto erstellt
            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");
        }
        
        // Getter
        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 - nur von Auto aufrufbar
        private Motor(int leistung, String typ) {
            this.leistung = leistung;
            this.typ = typ;
        }
        
        public void starten() {
            System.out.println("Motor (" + typ + ", " + leistung + " PS) gestartet");
        }
        
        // Getter
        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; // Standarddruck
        }
        
        public void aufpumpen(double druck) {
            this.druck = druck;
            System.out.println("Reifen auf " + druck + " bar aufgepumpt");
        }
        
        // Getter
        public int getGroesse() { return groesse; }
        public double getDruck() { return druck; }
    }
}

4. Abhängigkeit (Dependency)

Abhängigkeiten zeigen Verwendungsbeziehungen zwischen Klassen.

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

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

' Abhängigkeit (gestrichelte Linie)
Bestellung ..> PreisRechner : verwendet >

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

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

Bestellung ..> Logger : loggt >
Bestellung ..> DatenbankService : speichert >

@enduml

Java-Implementierung von Abhängigkeiten

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); }
    }
    
    // Abhängigkeits-Klassen
    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. Vererbung (Inheritance)

Vererbung zeigt “ist-ein” Beziehungen zwischen Klassen.

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

' Konkrete Unterklassen
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-Implementierung von Vererbung

public class InheritanceExamples {
    
    // Abstrakte Basisklasse
    public abstract class Fahrzeug {
        protected String marke;
        protected int baujahr;
        
        public Fahrzeug(String marke, int baujahr) {
            this.marke = marke;
            this.baujahr = baujahr;
        }
        
        // Abstrakte Methoden
        public abstract void fahren();
        public abstract void bremsen();
        
        // Konkrete Methode
        public String getInfo() {
            return marke + " aus " + baujahr;
        }
        
        // Getter
        public String getMarke() { return marke; }
        public int getBaujahr() { return baujahr; }
    }
    
    // Konkrete Unterklassen
    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. Implementierung (Implementation)

Implementierung zeigt die Beziehung zwischen Interfaces und implementierenden Klassen.

@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-Implementierung von Interfaces

public class InterfaceExamples {
    
    // Interfaces
    public interface Fliegend {
        void fliegen();
        void landen();
    }
    
    public interface Schwimmend {
        void schwimmen();
        void tauchen();
    }
    
    // Einfache Implementierung
    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; }
    }
    
    // Mehrere Interfaces implementieren
    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; }
    }
    
    // Abstrakte Klasse mit 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; }
    }
    
    // Konkrete Unterklasse
    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; }
    }
}

Komplexe Klassendiagramme

Vollständiges Beispiel: Universitätssystem

@startuml
' Abstrakte Basisklassen
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
}

' Konkrete Klassen
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
}

' Weitere Klassen
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
}

' Beziehungen
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 >

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

@enduml

Java-Implementierung des Universitätssystems

public class UniversitySystem {
    
    // Abstrakte Basisklasse
    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; }
    }
    
    // Abstrakte Mitarbeiter-Klasse
    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; }
    }
    
    // Konkrete Klassen
    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); // Zufallsnote 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; }
    }
    
    // Weitere Klassen
    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; // Noch nicht benotet
        }
        
        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 für UML-Klassendiagramme

1. Konsistente Namenskonventionen

// 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. Verantwortlichkeiten trennen

@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. Vermeidung von zyklischen Abhängigkeiten

@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

Prüfungsrelevante Konzepte

Wichtige Beziehungsarten

| Beziehungstyp | Symbol | Bedeutung | Lebensdauer |
|---------------|--------|-----------|-------------|
| Assoziation | ---- | Strukturelle Beziehung | Unabhängig |
| Aggregation | o-- | "hat-ein" (teilweise) | Unabhängig |
| Komposition | *-- | "hat-ein" (ganz) | Abhängig |
| Abhängigkeit | ..> | "verwendet" | Temporär |
| Vererbung | < |-- | "ist-ein" | Permanent |
| Implementierung | ..|> | "implementiert" | Permanent |

Typische Prüfungsaufgaben

  1. Zeichnen Sie Klassendiagramme für gegebene Szenarien
  2. Identifizieren Sie Beziehungsarten
  3. Implementieren Sie Beziehungen in Java
  4. Refaktorieren Sie schlechte Designs
  5. Erklären Sie Unterschiede zwischen Aggregation und Komposition

Zusammenfassung

UML-Klassendiagramme sind essentiell für Softwarearchitektur:

  • Assoziation: Strukturelle Beziehungen zwischen Klassen
  • Aggregation: “hat-ein” Beziehung, Teile können unabhängig existieren
  • Komposition: “hat-ein” Beziehung, Teile sind abhängig
  • Abhängigkeit: Verwendung von Klassen oder Interfaces
  • Vererbung: “ist-ein” Beziehung zwischen Klassen
  • Implementierung: Interface-Realisierung

Gutes Klassendesign folgt SOLID-Prinzipien und vermeidet zyklische Abhängigkeiten.

Zurück zum Blog
Share:

Ähnliche Beiträge