Menu
Coddy logo textTech

Kompositmuster

Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy. Lektion 75 von 87.

Das Composite Pattern ist ein strukturelles Entwurfsmuster, mit dem du Objekte zu Baumstrukturen zusammensetzen kannst, um Teil-Ganzes-Hierarchien darzustellen. Es ermöglicht Clients, einzelne Objekte und Zusammensetzungen von Objekten über eine gemeinsame Schnittstelle einheitlich zu behandeln.

Stell dir ein Dateisystem vor: Ein Ordner kann Dateien und andere Ordner enthalten, die wiederum weitere Dateien und Ordner enthalten können. Unabhängig davon, ob du mit einer einzelnen Datei oder einer gesamten Ordnerstruktur arbeitest, möchtest du Vorgänge wie „Größe abrufen“ auf dieselbe Weise ausführen. Das Muster definiert eine Component-Schnittstelle, Leaf-Objekte (einzelne Elemente) und Composite-Objekte (Container, die untergeordnete Elemente enthalten):

interface FileComponent {
    void display(String indent);
    int getSize();
}

class File implements FileComponent {
    private String name;
    private int size;
    
    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }
    
    public void display(String indent) {
        System.out.println(indent + name + " (" + size + "KB)");
    }
    
    public int getSize() {
        return size;
    }
}

class Folder implements FileComponent {
    private String name;
    private List<FileComponent> children = new ArrayList<>();
    
    public Folder(String name) {
        this.name = name;
    }
    
    public void add(FileComponent component) {
        children.add(component);
    }
    
    public void display(String indent) {
        System.out.println(indent + name + "/");
        for (FileComponent child : children) {
            child.display(indent + "  ");
        }
    }
    
    public int getSize() {
        return children.stream().mapToInt(FileComponent::getSize).sum();
    }
}

Das Komposit delegiert Operationen an seine untergeordneten Elemente und ermöglicht so rekursive Strukturen. Clients interagieren mit dem Baum, ohne zu wissen, ob sie mit einem Blatt oder einem Komposit arbeiten:

Folder root = new Folder("Documents");
root.add(new File("resume.pdf", 150));

Folder photos = new Folder("Photos");
photos.add(new File("vacation.jpg", 2000));
root.add(photos);

root.display("");
System.out.println("Total: " + root.getSize() + "KB");

Das Composite Pattern eignet sich ideal zur Darstellung von Hierarchien wie Organigrammen, UI-Komponenten oder Menüsystemen, bei denen Gruppen und Einzelpersonen gleich behandelt werden müssen.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Organigrammsystem mithilfe des Composite Patterns! Du erstellst eine Struktur, in der Abteilungen Mitarbeiter und andere Unterabteilungen enthalten können. Dadurch kannst du Gesamtgehälter berechnen und die Hierarchie einheitlich anzeigen, unabhängig davon, ob du einen einzelnen Mitarbeiter oder eine ganze Abteilung betrachtest.

Du wirst deinen Code auf vier Dateien verteilen:

  • OrganizationComponent.java: Definiere die Komponentenschnittstelle, die sowohl von Mitarbeitern als auch von Abteilungen implementiert wird. Sie sollte zwei Methoden deklarieren: showDetails(String indent) zum Anzeigen der Komponente mit der passenden Einrückung und getSalary(), die das Gesamtgehalt als Ganzzahl zurückgibt.
  • Employee.java: Erstelle die Blattklasse, die einzelne Mitarbeiter repräsentiert. Ein Employee besitzt einen Namen (String) und ein Gehalt (int), die beide über den Konstruktor festgelegt werden. Wenn showDetails aufgerufen wird, sollte [indent][name]: $[salary] ausgegeben werden. Die Methode getSalary gibt einfach das Gehalt des Mitarbeiters zurück.
  • Department.java: Erstelle die zusammengesetzte Klasse, die sowohl Mitarbeiter als auch Unterabteilungen aufnehmen kann. Ein Department besitzt einen Namen (String) und verwaltet eine Liste von OrganizationComponent-Kindern. Es sollte eine Methode add(OrganizationComponent component) besitzen, um Mitglieder hinzuzufügen. Wenn showDetails aufgerufen wird, gibt sie [indent][name] Department aus und ruft anschließend für jedes Kind showDetails mit einer größeren Einrückung auf (zwei Leerzeichen zusätzlich). Die Methode getSalary gibt die Summe der Gehälter aller Kinder zurück.
  • Main.java: Baue deine Organisation auf! Du erhältst vier Eingaben: zwei Mitarbeiternamen mit ihren Gehältern sowie einen Namen für eine Unterabteilung mit einem Mitarbeiter.

    Erstelle eine Abteilung „Engineering“ als Wurzel. Füge ihr mithilfe der ersten beiden Name-Gehalt-Paare zwei Mitarbeiter hinzu. Erstelle anschließend mithilfe der dritten Eingabe eine Unterabteilung, füge ihr mithilfe des vierten Name-Gehalt-Paars einen Mitarbeiter hinzu und füge diese Unterabteilung zu Engineering hinzu.

    Rufe showDetails("") für die Abteilung Engineering auf und gib anschließend das Gesamtgehalt im Format Total Salary: $[amount] aus.

Du erhältst die Eingaben in dieser Reihenfolge: Name von employee1 (String), Gehalt von employee1 (int), Name von employee2 (String), Gehalt von employee2 (int), Name der Unterabteilung (String), Name von employee3 (String), Gehalt von employee3 (int).

Bei den Eingaben Alice, 75000, Bob, 65000, QA, Charlie, 55000 würde deine Ausgabe beispielsweise wie folgt aussehen:

Engineering Department
  Alice: $75000
  Bob: $65000
  QA Department
    Charlie: $55000
Total Salary: $195000

Beachte, wie dieselben Methoden showDetails und getSalary nahtlos funktionieren, unabhängig davon, ob sie für einen einzelnen Mitarbeiter oder eine gesamte Abteilung mit verschachtelten Unterabteilungen aufgerufen werden. Die zusammengesetzte Struktur übernimmt die Rekursion automatisch, sodass du die gesamte Hierarchie einheitlich behandeln kannst!

Probier es selbst

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Eingaben lesen
        String emp1Name = scanner.nextLine();
        int emp1Salary = Integer.parseInt(scanner.nextLine());
        String emp2Name = scanner.nextLine();
        int emp2Salary = Integer.parseInt(scanner.nextLine());
        String subDeptName = scanner.nextLine();
        String emp3Name = scanner.nextLine();
        int emp3Salary = Integer.parseInt(scanner.nextLine());
        
        // TODO: Create the "Engineering" department as the root
        
        // TODO: Erstelle und füge zwei Mitarbeiter zu Engineering mit den emp1- und emp2-Daten hinzu
        
        // TODO: Erstelle eine Unterabteilung mit subDeptName
        
        // TODO: Erstelle und füge einen Mitarbeiter zur Unterabteilung mit den emp3-Daten hinzu
        
        // TODO: Füge die Unterabteilung zu Engineering hinzu
        
        // TODO: Call showDetails("") on the Engineering department
        
        // TODO: Gib das Gesamtgehalt im Format aus: Total Salary: $[amount]
    }
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Java-Compiler