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.