- 1 Section
- 10 Lessons
- unbegrenzt
- Objektorientierte Programmierung (OOP)10
Polymorphismus
Polymorphismus ist die dritte Säule der OOP – und für viele Anfänger die mysteriöseste. Das Wort klingt nach Theorie, das Konzept ist aber überraschend praktisch: verschiedene Objekte reagieren unterschiedlich auf die gleiche Nachricht. Du hast es in L5 beim Method Overriding schon angeschnitten – Polymorphismus ist die Frucht, die daraus erwächst.
Diese Lektion zeigt dir die verschiedenen Arten von Polymorphismus, das Liskov-Substitutionsprinzip, den Unterschied zwischen statischem und dynamischem Dispatch, und warum Polymorphismus die echte Macht der OOP ist – nicht Vererbung alleine.
1) Das Wort und sein Sinn
„Polymorphismus" kommt aus dem Griechischen: poly = viele, morphē = Form. „Vielgestaltigkeit". Auf Code übertragen: derselbe Methodenname produziert verschiedene Verhalten je nach Objekttyp.
Klassisches Beispiel: stell dir vor du hast eine Liste von Tieren. Du rufst auf jedem laut_geben() auf. Jeder Hund bellt, jede Katze miaut, jede Kuh muht. Dein Code macht aber überall dasselbe: tier.laut_geben(). Das ist Polymorphismus in Aktion:
tier.laut_geben()
if typ == "hund": bellen(); elif typ == "katze": miauen(). Bei jedem neuen Tier müsstest du den if-Block erweitern. Mit OOP fügst du einfach eine neue Tier-Klasse hinzu – der Schleifencode bleibt unverändert. Das nennt sich Open-Closed-Prinzip (siehe L9).2) Code-Beispiel: Tier-Hierarchie
So sieht der Code aus, der die Animation oben erzeugt. Beachte: nach der Schleife (Zeile 14) gibt es keinen if-else-Block. Python ruft laut_geben auf, und jedes Objekt weiß selbst was es zu tun hat:
Magisch. Der Code in der Schleife kennt die konkreten Klassen nicht. Er weiß nur: jedes Objekt hier hat eine laut_geben()-Methode. Welche aufgerufen wird, entscheidet die Laufzeit beim Auruf – das nennt sich dynamic dispatch.
3) Arten von Polymorphismus
Polymorphismus ist nicht ein einziges Konzept, sondern eine Sammelbezeichnung für mehrere Mechanismen:
add(int, int) vs. add(String, String). Java ja, Python nein.List<T> in Java, list[T] in Python (typing).int + double wird zu double + double. Bei Datenoperationen.4) Duck Typing
Python und andere dynamische Sprachen haben eine besondere Form des Polymorphismus: Duck Typing. Die Philosophie:
„If it walks like a duck and quacks like a duck, then it must be a duck."
Konkret: in Python interessiert sich der Code nicht für den Typ deiner Objekte. Hauptsache, das Objekt hat die Methode die aufgerufen wird. Du brauchst keine gemeinsame Oberklasse:
Java würde hier eine gemeinsame Oberklasse oder ein Interface verlangen. Python ist pragmatischer – wenn die Methode da ist, läuft's. Schneller zu schreiben, aber auch fehleranfälliger (Bug erst zur Laufzeit).
5) Static vs. Dynamic Dispatch
Wenn du tier.laut_geben() schreibst – wann wird entschieden welche Methode tatsächlich aufgerufen wird? Es gibt zwei Möglichkeiten:
virtual (dynamisch) – außer sie sind final oder static. In C++ musst du virtual explizit angeben.6) Liskov-Substitutionsprinzip
Eine fundamentale Regel: überall wo die Oberklasse erwartet wird, muss eine Unterklasse problemlos einsetzbar sein. Klingt banal, hat aber Folgen. Benannt nach Barbara Liskov, Turing-Award-Gewinnerin. Mehr in L9 SOLID.
Beispiel-Verstoß: du hast Vogel mit Methode fliegen(). Du erbst Pinguin von Vogel – aber Pinguine können nicht fliegen. Wenn dein Code jetzt überall vogel.fliegen() aufruft, schlägt's bei Pinguinen fehl. Verstoß gegen LSP:
Lösung: besseres Klassen-Design. Trenne Vogel in fliegende und nicht-fliegende. Oder nutze Interfaces wie FlyableTier, das nur fliegende Tiere implementieren.
7) Typumwandlung (Casting)
Polymorphismus erlaubt es, eine Unterklasse als Oberklasse zu behandeln. Manchmal will man später wieder zurück – das nennt sich Casting oder Downcasting:
instanceof (Java) oder isinstance() (Python) prüfen.8) Polymorphismus und Schnittstellen
Polymorphismus arbeitet besonders gut mit Interfaces (Thema von L7). Interfaces sind Verträge: „dieses Objekt kann diese Methoden". Verschiedene Klassen können das gleiche Interface implementieren:
Rechnung und Gehalt haben nichts miteinander zu tun – aber beide sind „zahlbar". Der Buchhaltungs-Code kann sie gleich behandeln. Das ist Polymorphismus über Interfaces. Sehr mächtig.
9) Praktische Vorteile
Warum lieben Profis Polymorphismus? Drei konkrete Gewinne:
- Erweiterbarkeit: neuer Tier-Typ? Einfach neue Klasse hinzufügen, bestehende Code-Stellen mit der Schleife funktionieren weiter.
- Code-Reduktion: keine if-elif-else-Ketten mehr für „welcher Typ ist das?". Die Klassen wissen selbst was zu tun ist.
- Testbarkeit: in Tests kannst du Fake-Objekte (Mocks) einsetzen, die das Interface erfüllen aber kein echtes Verhalten haben – isolierte Tests werden einfach.
Faustregel: überall wo du eine Typ-Abfrage mit if-elif-else schreibst, könnte Polymorphismus eine bessere Lösung sein. Das ist nicht immer der Fall – aber oft.
10) Häufige Klausurfragen
Klassiker für IHK-Prüfungen:
- „Definiere Polymorphismus." → Vielgestaltigkeit: gleiche Methode, verschiedene Implementierungen je nach Objekttyp
- „Was ist Method Overriding?" → Unterklasse ersetzt eine Methode der Oberklasse mit gleichem Namen und Signatur
- „Unterschied zwischen Overriding und Overloading?" → Overriding: Vererbung (gleiche Signatur, andere Klasse). Overloading: gleicher Name, andere Parameter, gleiche Klasse
- „Was ist dynamic dispatch?" → Auflösung welche Methode aufgerufen wird, anhand des konkreten Objekt-Typs zur Laufzeit
- „Was ist das Liskov-Prinzip?" → Unterklassen müssen Oberklassen ersetzbar sein, ohne dass Aufrufer-Code bricht
- „Welche Vorteile bringt Polymorphismus?" → Erweiterbarkeit, Code-Reduktion, Open-Closed-Prinzip, einfacheres Testen
- „Was ist Duck Typing?" → dynamische Sprachen: wenn ein Objekt die nötigen Methoden hat, wird's akzeptiert. Kein explizites Interface nötig
Zusammenfassung
Polymorphismus = „Vielgestaltigkeit": gleiche Methodenname, verschiedenes Verhalten je nach Objekttyp. Vier Arten: Subtyp (klassisch über Vererbung), Ad-hoc (Überladung), parametrisch (Generics), Coercion (Typumwandlung). Method Overriding ist die Basis für Subtyp-Polymorphismus. Dynamic Dispatch entscheidet zur Laufzeit welche Methode aufgerufen wird. Duck Typing in Python: nicht der Typ zählt, sondern ob die Methode vorhanden ist. Liskov-Prinzip: Unterklassen müssen Oberklassen ersetzen können ohne dass Aufrufer brechen. Upcasting (Sub→Super) ist immer sicher, Downcasting braucht Prüfung. Polymorphismus ist die echte Macht der OOP – Vererbung ist nur das Mittel dazu.
