Nach dieser Lektion kannst du
Der Begriff Polymorphie stammt aus dem Griechischen und bedeutet wörtlich „Vielgestaltigkeit“ oder „viele Formen“. In der objektorientierten Programmierung beschreibt Polymorphie die Möglichkeit, dass derselbe Methodenname je nach Situation ein unterschiedliches Verhalten besitzt.
Das klingt zunächst kompliziert, begegnet uns aber ständig. Stell dir folgende Methode vor: fortbewegen(). Jedes Tier kann sich fortbewegen, doch nicht jedes Tier bewegt sich auf dieselbe Weise.
Ein Hund rennt. Ein Vogel fliegt. Ein Fisch schwimmt. Alle besitzen also dieselbe Methode, führen sie aber unterschiedlich aus. Genau das versteht man unter Polymorphie.
In vielen klassischen Programmen würde man jeder Aktion einen eigenen Namen geben:
hundRennt()
vogelFliegt()
fischSchwimmt()
In der objektorientierten Programmierung genügt dagegen ein gemeinsamer Methodenname:
fortbewegen()
Welche konkrete Variante ausgeführt wird, entscheidet sich erst später. Dadurch werden Programme deutlich flexibler und leichter erweiterbar.
Der einfachste Fall von Polymorphie besteht darin, dass verschiedene Klassen Methoden mit demselben Namen besitzen. Beispielsweise könnten sowohl ein Hund als auch ein Auto eine Methode starten() besitzen.
Da beide Methoden zu unterschiedlichen Klassen gehören, entsteht kein Konflikt.
Jetzt kommen wir zu unserem bisherigen Beispiel. In der Klasse Tier haben wir bereits die Methode + fortbewegen() kennengelernt. Natürlich bewegt sich aber nicht jedes Tier gleich. Deshalb kann eine Unterklasse die geerbte Methode überschreiben. Man spricht vom Method Overriding.
Obwohl fortbewegen() bereits in der Oberklasse vorhanden ist, darf sie in der Unterklasse erneut definiert werden. Die neue Implementierung ersetzt dann die ursprüngliche Version.
| Klasse | Verhalten von fortbewegen() |
|---|---|
| Tier | „Das Tier bewegt sich.“ |
| Hund | „Der Hund rennt auf vier Pfoten.“ |
Die Methode besitzt also denselben Namen, führt aber je nach Klasse etwas anderes aus.
Eine weitere Form der Polymorphie ist das Method Overloading. Dabei besitzt eine einzige Klasse mehrere Methoden mit demselben Namen. Unterschieden werden sie durch ihre Parameter.
Alle Methoden heißen fressen, trotzdem handelt es sich um unterschiedliche Methoden. Sie werden anhand ihrer Parameter unterschieden:
fressen() – Der Hund frisst.fressen("Knochen") – Der Hund frisst einen Knochen.fressen(3) – Der Hund frisst drei Portionen.Dadurch bleibt die Benennung konsistent, obwohl unterschiedliche Situationen behandelt werden.
Hier gibt es jedoch einen wichtigen Unterschied zwischen Programmiersprachen. Java unterstützt Method Overloading direkt – dort dürfen mehrere Methoden mit demselben Namen existieren, solange sich ihre Parameter unterscheiden.
// Java
void fressen() { ... }
void fressen(String futter) { ... }
void fressen(int menge) { ... }
Python funktioniert anders. Python ist dynamisch typisiert – Datentypen werden erst zur Laufzeit festgelegt, nicht bereits beim Übersetzen des Programms. Dadurch kann Python nicht allein anhand der Parameter entscheiden, welche von mehreren gleichnamigen Methoden gemeint ist. Aus diesem Grund unterstützt Python kein echtes Method Overloading.
In Python wird stattdessen häufig mit Standardparametern gearbeitet, um ein ähnliches Verhalten zu erreichen:
# Python
def fressen(self, futter=None, menge=1):
if futter:
print(f"Der Hund frisst {futter}")
else:
print(f"Der Hund frisst {menge} Portionen")
Overriding und Overloading klingen ähnlich, meinen aber Unterschiedliches: Beim Overriding überschreibt eine Unterklasse eine geerbte Methode (gleicher Name, gleiche Parameter, andere Klasse). Beim Overloading besitzt dieselbe Klasse mehrere Methoden mit gleichem Namen, aber unterschiedlichen Parametern.
Für UML spielt dieser Unterschied zwischen Java und Python jedoch keine Rolle. Ein UML-Klassendiagramm beschreibt zunächst nur das objektorientierte Modell und ist unabhängig von einer konkreten Programmiersprache.
Die vielleicht wichtigste Form der Polymorphie nennt sich dynamische Bindung. Dabei entscheidet sich erst während der Programmausführung, welche Methode tatsächlich ausgeführt wird.
Angenommen, eine Variable besitzt den Typ Tier. Tatsächlich verweist sie aber auf ein Objekt der Klasse Hund:
// Java
Tier tier = new Hund();
tier.fortbewegen();
Obwohl die Variable den Typ Tier besitzt, wird nicht die Methode aus der Klasse Tier ausgeführt. Stattdessen erkennt das Programm zur Laufzeit, dass sich dahinter ein Hund befindet. Deshalb wird die Methode Hund.fortbewegen() aufgerufen.
In Python entfällt die explizite Typangabe, das Prinzip bleibt aber dasselbe:
# Python
tier = Hund()
tier.fortbewegen() # ruft automatisch Hund.fortbewegen() auf
Die Entscheidung erfolgt also dynamisch zur Laufzeit. Gerade dieses Verhalten macht objektorientierte Programme besonders flexibel: Neue Unterklassen können ergänzt werden, ohne dass bestehender Code angepasst werden muss.
| Art | Beschreibung |
|---|---|
| Gleiche Methodennamen in verschiedenen Klassen | Unterschiedliche Klassen dürfen gleichnamige Methoden besitzen. |
| Method Overriding | Eine Unterklasse überschreibt eine geerbte Methode. |
| Method Overloading | Eine Klasse besitzt mehrere Methoden mit demselben Namen, aber unterschiedlichen Parametern (nicht in Python unterstützt). |
| Dynamische Bindung | Erst zur Laufzeit entscheidet sich, welche Methodenimplementierung tatsächlich ausgeführt wird. |
Mit dieser Lektion schließen die Lernenden die vier Grundkonzepte der objektorientierten Programmierung ab. Das bildet eine ideale Grundlage für das anschließende Kapitel, in dem UML-Klassendiagramme systematisch modelliert und komplexere Beziehungen wie Assoziation, Aggregation und Komposition behandelt werden.