Menu
Coddy logo textTech

Komposition vs. Vererbung

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

Im vorherigen Kapitel haben Sie gelernt, dass Traits eine „has-a“-Fähigkeit bieten, während Vererbung eine „is-a“-Beziehung herstellt. Komposition führt das „has-a“-Konzept weiter, indem sie komplexe Objekte aus einfacheren zusammensetzt und diese als Eigenschaften speichert, anstatt von ihnen zu erben.

Mit Vererbung könnte ein Car Vehicle erweitern. Bei der Komposition enthält ein Car ein Engine-Objekt:

<?php
class Engine {
    public function start(): string {
        return "Engine started";
    }
}

class Car {
    private Engine $engine;
    
    public function __construct() {
        $this->engine = new Engine();
    }
    
    public function start(): string {
        return $this->engine->start();
    }
}

$car = new Car();
echo $car->start();

Ausgabe:

Engine started

Die Klasse Car erbt nicht von Engine – sie besitzt eine. Dieser Ansatz bietet erhebliche Vorteile: Sie können den Motor gegen eine andere Implementierung austauschen, die Klassen bleiben lose gekoppelt und Sie vermeiden die starren Hierarchien, die durch tiefe Vererbung entstehen.

Ein gängiger Leitfaden in der OOP lautet "Bevorzugen Sie Komposition gegenüber Vererbung." Vererbung funktioniert gut für echte Typhierarchien (ein Dog ist wirklich ein Animal), aber Komposition glänzt, wenn Sie Funktionalität aus unabhängigen Teilen zusammenstellen. Sie können mehrere Objekte kombinieren, sie zur Laufzeit austauschen und Komponenten isoliert testen.

Die nächste Lektion befasst sich mit Dependency Injection, die direkt auf Komposition aufbaut, indem sie steuert, wie Objekte ihre Abhängigkeiten erhalten.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Computersystem mittels Komposition aufbauen, bei dem ein Computer aus separaten Komponentenobjekten zusammengesetzt wird, anstatt von ihnen zu erben. Dies zeigt, wie die Komposition es ermöglicht, komplexe Objekte aus einfacheren, unabhängigen Teilen aufzubauen.

Sie werden Ihren Code über drei Dateien organisieren:

  • Processor.php — Erstellen Sie eine Klasse Processor, die eine CPU repräsentiert. Verwenden Sie Constructor Promotion, um ein privates $model (String) und ein privates $cores (Integer) zu definieren. Fügen Sie eine Methode getSpecs() hinzu, die "{$this->model} ({$this->cores} cores)" zurückgibt.
  • Memory.php — Erstellen Sie eine Klasse Memory, die den Arbeitsspeicher repräsentiert. Verwenden Sie Constructor Promotion, um eine private $size (Integer, der GB repräsentiert) zu definieren. Fügen Sie eine Methode getCapacity() hinzu, die "{$this->size}GB RAM" zurückgibt.
  • main.php — Binden Sie beide Komponentendateien ein und erstellen Sie eine Klasse Computer, die Komposition verwendet. Der Computer sollte:
    • Ein Processor-Objekt und ein Memory-Objekt als private Eigenschaften speichern
    • Ein Prozessormodell, eine Kernanzahl und eine Speichergröße in seinem Konstruktor akzeptieren
    • Die Komponentenobjekte intern während der Konstruktion erstellen
    • Eine Methode describe() haben, die "Computer with " . $this->processor->getSpecs() . " and " . $this->memory->getCapacity() zurückgibt

    Sie erhalten drei Eingaben: ein Prozessormodell, eine Anzahl von Kernen und eine Speichergröße in GB. Erstellen Sie einen Computer mit diesen Spezifikationen und geben Sie das Ergebnis des Aufrufs von describe() aus.

Beachten Sie, dass der Computer nicht von Processor oder Memory erbt — er enthält sie. Diese "hat-ein"-Beziehung durch Komposition hält jede Komponente unabhängig und wiederverwendbar, während sie es dem Computer ermöglicht, Aufgaben bei Bedarf an seine Teile zu delegieren.

Spickzettel

Komposition baut komplexe Objekte aus einfacheren auf, indem sie diese als Eigenschaften speichert, anstatt von ihnen zu erben. Dies schafft eine „hat-ein“-Beziehung (has-a), bei der eine Klasse Instanzen anderer Klassen enthält.

Einfaches Beispiel für Komposition:

<?php
class Engine {
    public function start(): string {
        return "Engine started";
    }
}

class Car {
    private Engine $engine;
    
    public function __construct() {
        $this->engine = new Engine();
    }
    
    public function start(): string {
        return $this->engine->start();
    }
}

Die Klasse Car erbt nicht von Engine – sie besitzt eine. Dies hält Klassen lose gekoppelt und vermeidet starre Vererbungshierarchien.

Bevorzugen Sie Komposition gegenüber Vererbung: Vererbung funktioniert gut für echte Typhierarchien (ein Dog ist ein Animal), aber Komposition glänzt beim Zusammenstellen von Funktionalität aus unabhängigen Teilen. Sie können mehrere Objekte kombinieren, sie zur Laufzeit austauschen und Komponenten isoliert testen.

Probier es selbst

<?php
require_once 'Processor.php';
require_once 'Memory.php';

class Computer
{
    // TODO: Private Eigenschaften definieren, um Prozessor- und Speicherobjekte zu speichern

    // TODO: Der Konstruktor sollte das Prozessormodell, die Kernanzahl und die Speichergröße akzeptieren
    // und die Komponentenobjekte intern erstellen
    public function __construct()
    {
        // TODO: Prozessor- und Speicherobjekte erstellen und speichern
    }

    // TODO: Die Methode describe() implementieren, die Folgendes zurückgibt:
    // "Computer mit [Prozessorspezifikationen] und [Speicherkapazität]"
    public function describe(): string
    {
        // TODO: An Komponentenobjekte delegieren und formatierten String zurückgeben
    }
}

// Eingabe lesen
$processorModel = trim(fgets(STDIN));
$cores = intval(fgets(STDIN));
$memorySize = intval(fgets(STDIN));

// TODO: Einen Computer mit den angegebenen Spezifikationen erstellen und das Ergebnis von describe() 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