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.
Aufgabe
EinfachErstellen 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 undgetSalary(), die das Gesamtgehalt als Ganzzahl zurückgibt.Employee.java: Erstelle die Blattklasse, die einzelne Mitarbeiter repräsentiert. EinEmployeebesitzt einen Namen (String) und ein Gehalt (int), die beide über den Konstruktor festgelegt werden. WennshowDetailsaufgerufen wird, sollte[indent][name]: $[salary]ausgegeben werden. Die MethodegetSalarygibt einfach das Gehalt des Mitarbeiters zurück.Department.java: Erstelle die zusammengesetzte Klasse, die sowohl Mitarbeiter als auch Unterabteilungen aufnehmen kann. EinDepartmentbesitzt einen Namen (String) und verwaltet eine Liste vonOrganizationComponent-Kindern. Es sollte eine Methodeadd(OrganizationComponent component)besitzen, um Mitglieder hinzuzufügen. WennshowDetailsaufgerufen wird, gibt sie[indent][name] Departmentaus und ruft anschließend für jedes KindshowDetailsmit einer größeren Einrückung auf (zwei Leerzeichen zusätzlich). Die MethodegetSalarygibt 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 FormatTotal 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: $195000Beachte, 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]
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort thisMethodenFelder (Attribute)KonstruktormethodeÜberladen von KonstruktorenRückblick – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbung (extends)Das Schlüsselwort superÜberschreiben von Methoden (@Override)KonstruktorverkettungDie Object-KlasseEinfach- und mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenRückblick – Mitarbeiterhierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-SchnittstelleRückblick – Benutzerdefinierte Sortierung2Zugriffsmodifikatoren & Kapselung
Übersicht der ZugriffsebenenGetter- und Setter-MethodenInformationsverbergungDas Schlüsselwort finalRückblick – Bankkontoverwaltung5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenRückblick – Formrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, verschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Versiegelte Klassen (Java 17+)11Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBuilder-MusterObserver-MusterStrategie-Muster14Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungsdienst3Klassen-Props & statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Wiederholung – Counter & Utility6Schnittstellen & abstrakte Klassen
Einführung in InterfacesInterfaces implementierenMehrere Interfaces implementierenDefault & Static in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesRückblick – Zahlungssystem9Generics
Einführung in GenericsGenerische KlassenGenerische MethodenGebundene TypparameterWildcards (?, extends, super)Rückblick – Generischer Container12Entwurfsmuster Teil 2
BefehlsmusterAdaptermusterDekorierermusterSchablonenmethodenmusterZustandsmusterKompositmusterIteratormusterÜbe selbstständig: Online-Java-Compiler