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 startedDie 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.
Aufgabe
EinfachLassen 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 KlasseProcessor, 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 MethodegetSpecs()hinzu, die"{$this->model} ({$this->cores} cores)"zurückgibt.Memory.php— Erstellen Sie eine KlasseMemory, die den Arbeitsspeicher repräsentiert. Verwenden Sie Constructor Promotion, um eine private$size(Integer, der GB repräsentiert) zu definieren. Fügen Sie eine MethodegetCapacity()hinzu, die"{$this->size}GB RAM"zurückgibt.main.php— Binden Sie beide Komponentendateien ein und erstellen Sie eine KlasseComputer, die Komposition verwendet. DerComputersollte:- Ein
Processor-Objekt und einMemory-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
Computermit diesen Spezifikationen und geben Sie das Ergebnis des Aufrufs vondescribe()aus.- Ein
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
?>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 $this-SchlüsselwortMethodenEigenschaftenKonstruktor (__construct)Destruktor (__destruct)Rückblick - Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDas parent:: SchlüsselwortMethoden überschreibenDas final SchlüsselwortAbstrakte KlassenZusammenfassung – Mitarbeiter-Hierarchie7Kapselung
Public, Protected, PrivateZugriffsmodifikatoren im DetailGetter und SetterInformation HidingConstructor Promotion (8.0)Zusammenfassung – Studentenverwaltungssystem10Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungDependency InjectionAnonyme KlassenEnums (PHP 8.1)Fibers (PHP 8.1)Objekt-Klonen im DetailGeneratoren & Iteratoren2Namensräume & Autoloading
Einführung in NamensräumeDas use-SchlüsselwortPSR-4 Autoloading-StandardComposer AutoloaderZusammenfassung – Organisiertes Projekt5Interfaces & Verträge
Einführung in InterfacesInterfaces implementierenMehrfache Interface-ImplementierungInterface vs. Abstrakte KlasseType Hinting mit InterfacesZusammenfassung – Formen-Rechner8Magische Methoden
Einführung in magische Methoden__toString & __debugInfo__get, __set, __isset, __unset__call & __callStatic__clone & Objekt-Klonen__serialize & __unserializeZusammenfassung - Eigene Collection11Typsystem & Fehlerbehandlung
TypdeklarationenNullable-TypenUnion- & Intersection-TypenException-KlassenEigene Exception-HierarchieTry, Catch, FinallyZusammenfassung - Formular-Validator14Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Klasseneigenschaften
Instanz- vs. statische EigenschaftenKonstanten in KlassenStatische Methoden & EigenschaftenPrivate & geschützte EigenschaftenReadonly-Eigenschaften (PHP 8.1)Zusammenfassung – Bankkonto-Manager6Polymorphismus
Method Overriding erneut betrachtetPolymorphismus über InterfacesType Hinting & Union TypesLate Static BindingZusammenfassung – Payment Processor9Traits
Einführung in TraitsVerwendung mehrerer TraitsKonfliktlösung bei TraitsAbstrakte Methoden in TraitsTraits vs. Vererbung12Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster15Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung