Menu
CoddyTech

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 Objektzusammensetzungen über eine gemeinsame Schnittstelle einheitlich zu behandeln.

Stell dir ein Dateisystem vor: Ein Ordner kann Dateien und weitere Ordner enthalten, die wiederum weitere Dateien und Ordner enthalten können. Egal, 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 Composite delegiert Operationen an seine untergeordneten Elemente und ermöglicht so rekursive Strukturen. Clients interagieren mit dem Baum, ohne wissen zu müssen, ob sie mit einem Blatt oder einem Composite 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-Muster eignet sich ideal zur Darstellung von Hierarchien wie Organigrammen, UI-Komponenten oder Menüsystemen, bei denen Gruppen und einzelne Elemente gleich behandelt werden müssen.

challenge icon

Aufgabe

Einfach

Erstellen wir mit dem Composite-Muster ein Organigrammsystem! Du erstellst eine Struktur, in der Abteilungen Mitarbeiter und weitere Unterabteilungen enthalten können. So kannst du die Gesamtgehälter berechnen und die Hierarchie einheitlich anzeigen, egal ob du einen einzelnen Mitarbeiter oder eine ganze Abteilung betrachtest.

Du verteilst deinen Code auf vier Dateien:

  • OrganizationComponent.java: Definiere die Komponentenschnittstelle, die sowohl Mitarbeiter als auch Abteilungen implementieren. 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 darstellt. Ein Employee hat einen Namen (String) und ein Gehalt (int), die beide über den Konstruktor festgelegt werden. Wenn showDetails aufgerufen wird, sollte die Methode [indent][name]: $[salary] ausgeben. Die Methode getSalary gibt einfach das Gehalt des Mitarbeiters zurück.
  • Department.java: Erstelle die Verbundklasse, die sowohl Mitarbeiter als auch Unterabteilungen enthalten kann. Ein Department hat einen Namen (String) und verwaltet eine Liste von OrganizationComponent-Elementen. Die Methode add(OrganizationComponent component) fügt Mitglieder hinzu. Wenn showDetails aufgerufen wird, gibt die Methode [indent][name] Department aus und ruft dann für jedes untergeordnete Element showDetails mit einer größeren Einrückung auf (füge zwei Leerzeichen hinzu). Die Methode getSalary gibt die Summe der Gehälter aller untergeordneten Elemente zurück.
  • Main.java: Baue deine Organisation auf! Du erhältst vier Eingaben: die Namen und Gehälter von zwei Mitarbeitern sowie den Namen einer Unterabteilung mit einem Mitarbeiter.

    Erstelle eine Abteilung namens "Engineering" als Wurzel. Füge ihr mithilfe der ersten beiden Namens-/Gehaltspaare zwei Mitarbeiter hinzu. Erstelle dann mithilfe der dritten Eingabe eine Unterabteilung, füge ihr mithilfe des vierten Namens-/Gehaltspaars einen Mitarbeiter hinzu und füge diese Unterabteilung zu Engineering hinzu.

    Rufe für die Abteilung Engineering showDetails("") 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äre deine Ausgabe zum Beispiel:

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

Beachte, dass dieselben Methoden showDetails und getSalary problemlos funktionieren, egal ob sie für einen einzelnen Mitarbeiter oder eine ganze Abteilung mit verschachtelten Unterabteilungen aufgerufen werden. Die Verbundstruktur ü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 einlesen
        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: Die Abteilung "Engineering" als Wurzel erstellen
        
        // TODO: Mithilfe der Daten von emp1 und emp2 zwei Mitarbeiter erstellen und zu Engineering hinzufügen
        
        // TODO: Mithilfe von subDeptName eine Unterabteilung erstellen
        
        // TODO: Mithilfe der Daten von emp3 einen Mitarbeiter erstellen und zur Unterabteilung hinzufügen
        
        // TODO: Die Unterabteilung zu Engineering hinzufügen
        
        // TODO: showDetails("") für die Abteilung Engineering aufrufen
        
        // TODO: Das Gesamtgehalt im Format Total Salary: $[amount] ausgeben
    }
}
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