© saicle/Shutterstock.com
Kolumne: Quality Time

Von Weichen über Klassen


Die Buchstaben S und O der SOLID-Prinzipien [1] nach Robert C. Martin haben wir in unserer kleinen Serie in dieser Kolumne schon behandelt. Falls Sie die ersten beiden Teile der Serie zu diesen essenziellen Regeln der Objektorientierung verpasst haben, können Sie sie unter [2] und [3] nachlesen. Logischerweise folgt nun das L, das für das so genannte „Liskovsche Substitutionsprinzip“ steht.

Was seltsam klingt und einen sehr wissenschaftlich-mathematischen Hintergrund hat, erweist sich als eine der wichtigsten Regeln des objektorientierten Softwaredesigns. Sie besagt: Erwartet ein Stück Code ein Objekt einer bestimmten Klasse, so muss es auch mit beliebigen Instanzen von Ableitungen dieser Klasse umgehen können, ohne etwas davon zu wissen. Das klingt zunächst etwas abstrakt und lässt sich am besten an einem Beispiel erklären. Die folgende Klasse wird in einem Projekt zur Umrechnung von Entfernungsangaben verwendet:

class DistanceConverter { const FACTOR = 0.6214; public function milesToKilometers( $miles ) { return $miles / self::FACTOR; } }

Die einzige Methode der Klasse erwartet als Eingabe eine Fließkommazahl – eine Entfernung in Meilen – und gibt die konvertierte Kilometerangabe als Fließkommazahl zurück. Ein findiger Entwickler möchte nun zwei Comfort-Probleme dieser Klasse lösen: Zum einen ist die Umrechnung von negativen Distanzen für ihn wenig sinnvoll. Zweitens wird der Rückgabewert im Projekt sowieso nur zur Ausgabe an den Benutzer verwendet, sie kann daher auch direkt hübsch formatiert werden. Um diese beiden Features zu realisieren, baut der Entwickler eine Ableitung der Klasse:

class FormattingDistanceConverter extends DistanceConverer { public function milesToKilometers( $miles ) { if ( $miles < 0 ) { throw new InvalidArgumentException(); } return sprintf( '%01.2f C', parent::milesToKilometers( $miles ) ); } }

Was auf den ersten Blick nach einer sinnvollen Ableitung aussieht, kann ganz schnell in einer weißen Seite für den Benutzer oder, noch schlimmer, in einem Stack Trace enden. Denn Code, der auf einen DistanceConverter abgestimmt ist, rechnet nicht mit der nun eingeführten Exception. Und was passiert, wenn die Rückgabe der Methode milesToKilometers() früher oder später doch irgendwo im Projekt zu weiteren Berechnungen herangezogen wird? Die Definition der Basisklasse lässt diese Möglichkeit ja durchaus offen.

Was ist hier schief gelaufen? Genau, das Liskovsche Substitutionsprinzip wurde verletzt: Code, der einen DistanceConverter verlangt...

Neugierig geworden?

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang