Menu
Coddy logo textTech

Composite-Muster

Teil des Abschnitts Objektorientierte Programmierung der PHP-Journey von Coddy — Lektion 80 von 91.

Das Composite Pattern ist ein Strukturmuster, mit dem Sie Objekte zu Baumstrukturen zusammenfügen und diese Strukturen dann so behandeln können, als wären sie einzelne Objekte. Es eignet sich hervorragend zur Darstellung von Teil-Ganzes-Hierarchien, bei denen Sie Einzelobjekte und Objektgruppen einheitlich behandeln möchten.

Betrachten Sie ein Dateisystem. Ein Ordner kann Dateien und andere Ordner enthalten.

Wenn Sie die Gesamtgröße berechnen, möchten Sie dieselbe Methode sowohl für Dateien als auch für Ordner aufrufen, und Ordner sollten ihren Inhalt rekursiv aufsummieren. Das Composite Pattern macht dies nahtlos möglich, indem es sowohl Blättern (Dateien) als auch Komposita (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 können Sie Baumstrukturen aufbauen und diese 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:

1810

Der Client-Code ruft getSize() auf, ohne sich darum zu kümmern, ob es sich um eine einzelne Datei oder eine tief verschachtelte Ordnerstruktur handelt. Das Muster verarbeitet die Rekursion intern, was die Arbeit mit komplexen Hierarchien erleichtert.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Organigramm-System mit dem Composite Pattern erstellen. Unternehmen haben eine hierarchische Struktur, in der Abteilungen Mitarbeiter und andere Unterabteilungen enthalten können – eine perfekte Baumstruktur, in der Sie Summen einheitlich über die gesamte Organisation hinweg berechnen möchten.

Sie werden Ihren Code auf vier Dateien verteilen:

  • OrganizationUnit.php — Definieren Sie ein OrganizationUnit-Interface, das sowohl einzelne Mitarbeiter als auch Abteilungen implementieren werden. Es sollte zwei Methoden haben: getName(): string und getSalary(): int. Dieses gemeinsame Interface ermöglicht es Ihnen, einzelne Mitarbeiter und ganze Abteilungen bei der Kostenberechnung gleich zu behandeln.
  • Employee.php — Binden Sie das OrganizationUnit-Interface ein und erstellen Sie eine Klasse Employee, die es implementiert. Ein Mitarbeiter ist ein Blattknoten in Ihrem Organisationsbaum – er hat einen Namen und ein Gehalt, kann aber keine anderen Einheiten enthalten. Verwenden Sie Constructor Promotion, um den Namen und das Gehalt zu akzeptieren, und implementieren Sie beide Interface-Methoden.
  • Department.php — Binden Sie das OrganizationUnit-Interface ein und erstellen Sie eine Klasse Department, die es implementiert. Eine Abteilung ist ein Kompositum, das sowohl Mitarbeiter als auch andere Abteilungen enthalten kann. Ihre Abteilung sollte:
    • Einen Namen in ihrem Konstruktor akzeptieren
    • getName() implementieren, um den Namen der Abteilung zurückzugeben
    • Eine Methode add(OrganizationUnit $unit): void haben, um Mitarbeiter oder Unterabteilungen hinzuzufügen
    • getSalary() implementieren, um das Gesamtgehalt aller darin enthaltenen Einheiten zurückzugeben (indem alles darin enthaltene rekursiv summiert wird)
  • main.php — Binden Sie die Dateien Employee und Department ein. Sie erhalten eine Eingabe: einen JSON-String, der die Organisationsstruktur darstellt.

    Das JSON wird in diesem Format vorliegen:

    {"Engineering": [{"name": "Alice", "salary": 80000}, {"name": "Bob", "salary": 75000}], "Sales": [{"name": "Carol", "salary": 65000}]}

    Jeder Schlüssel ist ein Abteilungsname, und sein Wert ist ein Array von Mitarbeitern mit ihren Namen und Gehältern.

    Erstellen Sie ein Wurzel-Department namens "Company". Erstellen Sie für jede Abteilung im JSON ein Department, fügen Sie dessen Mitarbeiter hinzu und fügen Sie diese Abteilung dann der Company hinzu. Geben Sie schließlich das Gesamtgehalt des Unternehmens in diesem Format aus:

    Total Salary: [amount]

Das Schöne am Composite Pattern ist, dass der Aufruf von getSalary() für die Abteilung Company 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 Wurzel-Department namens "Company"

// TODO: Durchlaufe jedes Department in den JSON-Daten
// Für jedes Department:
//   - Erstelle ein neues Department-Objekt
//   - Füge jeden Employee zu diesem Department hinzu
//   - Füge das Department zur Company hinzu

// 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