Kompositummuster
Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy. Lektion 80 von 91.
Das Composite Pattern ist ein strukturelles Entwurfsmuster, mit dem du Objekte zu Baumstrukturen zusammensetzen und anschließend mit diesen Strukturen so arbeiten kannst, als wären sie einzelne Objekte. Es eignet sich perfekt zur Darstellung von Teil-Ganzes-Hierarchien, bei denen du einzelne Objekte und Objektgruppen einheitlich behandeln möchtest.
Betrachte ein Dateisystem. Ein Ordner kann Dateien und andere Ordner enthalten.
Wenn du die Gesamtgröße berechnest, möchtest du dieselbe Methode sowohl für Dateien als auch für Ordner aufrufen, wobei Ordner den Inhalt rekursiv summieren sollen. Das Kompositum-Muster macht dies nahtlos möglich, indem es sowohl Blättern (Dateien) als auch Kompositen (Ordnern) dieselbe Schnittstelle gibt.
<?php
interface FileSystemItem {
public function getName(): string;
public function getSize(): int;
}
class File implements FileSystemItem {
public function __construct(
private string $name,
private int $size
) {}
public function getName(): string {
return $this->name;
}
public function getSize(): int {
return $this->size;
}
}
class Folder implements FileSystemItem {
private array $items = [];
public function __construct(private string $name) {}
public function getName(): string {
return $this->name;
}
public function add(FileSystemItem $item): void {
$this->items[] = $item;
}
public function getSize(): int {
$total = 0;
foreach ($this->items as $item) {
$total += $item->getSize();
}
return $total;
}
}
Jetzt kannst du Baumstrukturen erstellen und einheitlich behandeln:
<?php
$docs = new Folder("Documents");
$docs->add(new File("resume.pdf", 250));
$docs->add(new File("cover.docx", 50));
$images = new Folder("Images");
$images->add(new File("photo.jpg", 1500));
$root = new Folder("Root");
$root->add($docs);
$root->add($images);
$root->add(new File("readme.txt", 10));
echo $root->getSize();
Ausgabe:
1810Der Client-Code ruft getSize() auf, ohne sich darum zu kümmern, ob er mit einer einzelnen Datei oder einer tief verschachtelten Ordnerstruktur arbeitet. Das Muster verarbeitet die Rekursion intern und macht den Umgang mit komplexen Hierarchien einfach.
Aufgabe
EinfachErstellen wir ein Organigrammsystem mithilfe des Composite Patterns. Unternehmen haben eine hierarchische Struktur, in der Abteilungen Mitarbeiter und andere Unterabteilungen enthalten können: eine perfekte Baumstruktur, bei der du Summen einheitlich über die gesamte Organisation hinweg berechnen möchtest.
Du wirst deinen Code auf vier Dateien verteilen:
OrganizationUnit.php: Definiere einOrganizationUnit-Interface, das sowohl einzelne Mitarbeiter als auch Abteilungen implementieren. Es sollte zwei Methoden enthalten:getName(): stringundgetSalary(): int. Dieses gemeinsame Interface ermöglicht es dir, einzelne Mitarbeiter und ganze Abteilungen bei der Kostenberechnung auf dieselbe Weise zu behandeln.Employee.php: Binde das OrganizationUnit-Interface ein und erstelle eineEmployee-Klasse, die es implementiert. Ein Mitarbeiter ist ein Blattknoten in deinem Organisationsbaum. Er hat einen Namen und ein Gehalt, kann aber keine anderen Einheiten enthalten. Verwende Konstruktor-Promotion, um den Namen und das Gehalt entgegenzunehmen, und implementiere beide Interface-Methoden.Department.php: Binde das OrganizationUnit-Interface ein und erstelle eineDepartment-Klasse, die es implementiert. Eine Abteilung ist ein Kompositum, das sowohl Mitarbeiter als auch andere Abteilungen enthalten kann. Deine Abteilung sollte:- einen Namen in ihrem Konstruktor entgegennehmen
getName()implementieren, um den Namen der Abteilung zurückzugeben- über eine Methode
add(OrganizationUnit $unit): voidverfügen, um Mitarbeiter oder Unterabteilungen hinzuzufügen getSalary()implementieren, um das Gesamtgehalt aller enthaltenen Einheiten zurückzugeben (indem rekursiv alles innerhalb der Abteilung summiert wird)
main.php: Binde die Dateien Employee und Department ein. Du erhältst eine Eingabe: einen JSON-String, der die Organisationsstruktur darstellt.Das JSON hat dieses Format:
{"Engineering": [{"name": "Alice", "salary": 80000}, {"name": "Bob", "salary": 75000}], "Sales": [{"name": "Carol", "salary": 65000}]}Jeder Schlüssel ist der Name einer Abteilung, und sein Wert ist ein Array von Mitarbeitern mit ihren Namen und Gehältern.
Erstelle eine Stamm-
Departmentnamens"Company". Erstelle für jede Abteilung im JSON eineDepartment-Instanz, füge ihre Mitarbeiter hinzu und füge diese Abteilung anschließend zu Company hinzu. Gib schließlich das Gesamtgehalt des Unternehmens in diesem Format aus:Total Salary: [amount]
Das Besondere am Composite Pattern ist, dass der Aufruf von getSalary() für die Company-Abteilung automatisch die Summe über alle verschachtelten Abteilungen und Mitarbeiter berechnet: Der Client-Code muss die interne Struktur nicht kennen.
Probier es selbst
<?php
require_once 'Employee.php';
require_once 'Department.php';
// Lies die JSON-Eingabe
$input = trim(fgets(STDIN));
$data = (array)json_decode($input, true);
// TODO: Erstelle ein Root-Department namens "Company"
// TODO: Durchlaufe jedes Department in den JSON-Daten
// Für jedes Department:
// - Erstelle ein neues Department-Objekt
// - Füge jeden Mitarbeiter zu diesem Department hinzu
// - Füge das Department zur Company hinzu
// 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 OOPKlassen vs. ObjekteDas Schlüsselwort $thisMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick – Einfacher Taschenrechner4Vererbung
Grundlegende VererbungDas Schlüsselwort parent::MethodenüberschreibungDas Schlüsselwort finalAbstrakte KlassenRückblick – Mitarbeiterhierarchie7Kapselung
Öffentlich, geschützt, privatZugriffsmodifikatoren im DetailGetter und SetterInformationsverbergungKonstruktor-Promotion (8.0)Wiederholung – System zur Verwaltung von Schülerdatensätzen10Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungDependency InjectionAnonyme KlassenEnums (PHP 8.1)Fibers (PHP 8.1)Objektklonen im DetailGeneratoren & Iteratoren13Entwurfsmuster Teil 2
BefehlsmusterAdaptermusterDekorierermusterSchablonenmethodenmusterZustandsmusterKompositummusterRepository-Muster2Namespaces & Autoloading
Einführung in NamespacesDas use-SchlüsselwortPSR-4-Autoloading-StandardComposer-AutoloaderRückblick – Organisiertes Projekt5Schnittstellen & Verträge
Einführung in SchnittstellenSchnittstellen implementierenMehrere Schnittstellen implementierenSchnittstelle vs. abstrakte KlasseTyp-Hinweise mit SchnittstellenRückblick – Formrechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objektklonen__serialize & __unserializeRückblick – Benutzerdefinierte Sammlung11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenBenutzerdefinierte Exception-HierarchieTry, Catch, FinallyRückblick – Formularvalidator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klassen-Eigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenSchreibgeschützte Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphie
Methodenüberschreibung erneut betrachtetPolymorphie über SchnittstellenTyp-Hinweise & Union-TypenSpätes statisches BindenRückblick – Zahlungsabwickler9Traits
Einführung in TraitsMehrere Traits verwendenAuflösung von Trait-KonfliktenAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschließende Herausforderungen
E-Learning-PlattformBankingsystemEntwicklung einer SpielfigurFahrzeugvermietungÜbe selbstständig: Online-PHP-Compiler