Sven Rautenberg: PDO Klassesen: Eine oder mehere Klassen?

Beitrag lesen

Moin!

Vererbung ist in OOP leider genau das Beispiel, mit dem man die Einsteiger in Tutorials bombardiert, es führt aber zu schlechtem Code.

Um das mal auszuführen: In Tutorials werden gerne "Autos" als Beispiel herangezogen.

class Fahrzeug {}

class Auto extends Fahrzeug {}
class Sportwagen extends Auto {}

class LKW extends Fahrzeug {}

Es wird dann im weitern Verlauf darüber philosophiert, dass Fahrzeuge als Eigenschaft beispielsweise die Anzahl von Rädern haben (weswegen man als Fahrzeug auch Motorräder machen könnte), oder die Anzahl von Sitzplätzen. LKW haben vielleicht noch einen Ladungstyp und maximale Zuladung, und Sportwagen eine Höchstgeschwindigkeit.

Dabei ist immer im Hinterkopf zu behalten: Auch wenn objektorientierte Beispiele Real-Welt-Objekte verwenden, geht es ja nie darum, diese nachzubilden - es geht höchstens darum, deren elektronisches Abbild so zu bauen, wie die zu lösende Aufgabe es vorsieht.

Angenommen also, man möchte Transportprobleme lösen, so würde die Anzahl der Räder irrelevant sein, die Anzahl der Sitzplätze und/oder die Zuladung aber sehr wohl interessieren.

Reduzieren wir das Beispiel mal auf "Verreisen von Personen":

class Fahrzeug {
  protected $sitzplaetze = 1; // es gibt immer einen Fahrer
  protected $fahrgaeste = [];
}

class Auto extends Fahrzeug {
  protected $sitzplaetze = 4;
}
class Sportwagen extends Auto {
  protected $sitzplaetze = 2;
}

Die Frage der Ladekapazität wäre damit erschlagen. Man kann sich jetzt an der Klasse "Fahrzeug" Methoden ausdenken, die das Ein- und Aussteigen von Fahrgästen regelt und dafür sorgt, dass nur maximal die erlaubte Anzahl an Personen drin sitzt etc.

Eine wichtige Aufgabe beim Lösen von Transportproblemen ist aber, dass man VON A NACH B will. Deswegen gibt es:

class Fahrzeug {
  protected $sitzplaetze = 1; // es gibt immer einen Fahrer
  protected $fahrgaeste = [];

  public function fahreNach($zielbeschreibung) {}
}

Wenn man irgendwo hin fahren will, braucht man Navigationshilfen. Für dieses Beispiel soll als Realwelt-Abbild gelten: Das Fahrzeug braucht ein Navi.

So ein Navi ist komplizierter elektronischer Krams, der mit irgendwelchen Datenbanken und GPS-Satelliten eine Route ermittelt. Trotzdem würde man jetzt nicht sowas machen: class Fahrzeug extends Navi {} - was hat denn das Fahrzeug mit dem Navi gemeinsam? Man würde das Navi aber ins Fahrzeug tun, damit es im Fahrzeug benutzt wird.

class Fahrzeug {
  protected $sitzplaetze = 1; // es gibt immer einen Fahrer
  protected $fahrgaeste = [];
  protected $navi;

  public function __construct(Navi $navi) {
    $this->navi = $navi;
  }

  public function fahreNach($zielbeschreibung) {
    $route = $this->navi->holeFahranweisungen($zielbeschreibung);
    foreach ($route as $anweisung) {
      $this->fahre($anweisung);
    }
  }
}

Die Stärke von OOP liegt darin, dass komplexe Detaillösungen, als Objekt modelliert, nach außen ein eher simples Interface anbieten, und die inneren Vorgehensweisen - gerne mit weiteren Objekten für innere Detaillösungen - nach außen verbergen. Es interessiert die Insassen eines Fahrzeugs nicht, WIE das Navi es schafft, eine Liste von Fahranweisungen zu erzeugen. Vermutlich wird irgendwo eine Datenbank integriert sein, und ein GPS-Sensor.

Würde "Fahrzeug" von "Navi" erben, könnte man genau dieselben Sachen ebenfalls machen, es wäre dann statt $this->navi->holeFahranweisungen() einfach $this->holeFahranweisungen() zu schreiben in fahreNach().

Das Problem wäre jetzt aber, dass das Fahrzeugobjekt jetzt alle Methoden vom Navi anbietet. Außerhalb von "Fahrzeug" ginge jetzt also $fahrzeug->holeFahranweisungen() - aber wieso sollte ein FAHRZEUG jemand anderem FAHRANWEISUNGEN ausgeben können?

Deswegen ist es eine gute Vorgehensweise, mächtige Funktionalitäten in Objekten durch Zusammensetzen unterschiedlicher, aber voneinander unabhängiger Objekte zu realisieren: "Composition over Inheritance"

Wikipedia meint: "So ist es möglich, zur Laufzeit das Verhalten einer Klasse zu verändern." - was ja hier im Beispiel stimmt: Die Fähigkeiten des Navis sind nicht fest verdrahtet mit dem Fahrzeug, d.h. dem Fahrzeug kann man entweder ein einfaches Navi geben, was z.B. nur die vier Himmelsrichtungen für Anweisungen benutzt und toll für Offroad in der Wüste funktioniert, oder ein Straßennavi für Gegenden, wo Straßen existieren.

Grüße Sven