Ersetzbarkeitsprinzip

In der Regel wird die Klassenhierarchie einer intuitiven Hierarchie der beteiligten Objekte nachempfunden. So kann man zum Beispiel Square als Unterklasse von Rect definieren, da jedes Quadrat auch ein Rechteck ist.

Diese Idee kann man weiterführen und fordern, dass überall, wo ein Rect-Objekt verwendet wird auch ein Square-Objekt verwendet werden können sollte, ohne dass sich dadurch das Verhalten des Programms verändert. Intuitiv ist diese (Ersetzbarkeitsprinzip genannte) Forderung gerechtfertigt, wenn Quadrate sich immer wie Rechtecke verhalten. Da die Square-Klasse jedoch Rect-Methoden überschreiben kann, ist dies nicht automatisch gewährleistet, wie das folgende Beispiel zeigt.

Die Rect-Klasse bietet eine mutierende Zugriffsmethode set_width zum setzen der Breite eines Rechteck-Objektes. Es ist nicht sinnvoll, diese Methode in der Square-Klasse zu erben, da bei Veränderung der Breite (ohne gleichzeitiger Veränderung der Höhe) ein Square-Objekt kein Quadrat mehr darstellen würde. Die Square-Klasse sollte also die set_width-Methode so überschreiben, dass gleichzeitig auch die Höhe verändert wird und zwar so, dass die entstehende Figur ein Quadrat bleibt.

Durch diese Verhaltensänderung in der Unterklasse wird jedoch das genannte Ersetzbarkeitsprinzip verletzt, da sich nun Square-Objekte anders verhalten als Rect-Objekte, wenn auf ihnen die set_width-Methode aufgerufen wird.

>>> p = Point(100, 100)
>>> r = Rect(p, 150, 150)
>>> s = Square(p, 150)
>>> r.set_width(100)
>>> r.height()
150
>>> s.set_width(100)
>>> s.height()
100

Im Allgemeinen kann jedes Überschreiben einer Methode potentiell zu einer Verletzung des Ersetzbarkeitsprinzips führen. Nur wenn die neue Implementierung das Verhalten der alten nicht ändert (und zum Beispiel lediglich effizienter implementiert), bleibt das Ersetzbarkeitsprinzip in Gegenwart von überschriebenen Methoden gewahrt.