Was ist eigentlich Polymorphismus in der Informatik – ganz einfach erklärt!

Veröffentlicht: vor 3 monaten · Lesedauer ca. 10 Minuten

Beim Erlernen einer objektorientierten Programmiersprache, wirst du früher oder später auf diesen Begriff stoßen.

Polymorphismus

Was zunächst ziemlich schwierig klingt und blöd auszusprechen ist, ist eigentlich ganz einfach.

Der Duden erklärt es ganz plump mit „Vielgestaltigkeit„. Allerdings ist man hinterher genauso schlau wie vorher (ich jedenfalls).

Eigentlich ist es nur ein anderes Wort für Vererbung.

Dabei gilt es sowohl für Schnittstellen, als auch für abstrakte Klassen.

Polymorphismus mit abstrakten Klassen

Sagen wir mal, wir möchten ganz gerne in den Urlaub fahren.

Dafür erstellen wir zunächst eine Klasse Urlaub. Diese sieht wie folgt aus:

class Urlaub 
{
	public void SachenPacken() 
	{
		Console.WriteLine("Die Sachen für den Urlaub packen");
	}
}

Dann können wir bereits unsere Sachen packen und in den Urlaub fahren.

Urlaub urlaub = new Urlaub();
urlaub.SachenPacken();
// Ausgabe: Für den Urlaub Sachen packen

Urlaub ist toll. Aber um welchen Urlaub handelt es sich? Denn je nach Urlaubsart benötigt unterschiedlich viele Klamotten und auch mal ganz andere.

Also definieren wir uns mal eben zwei Arten vor Urlauben. Einmal ein Kurztrip und einmal ein Strandurlaub.

Beide Klassen definieren jeweils ihre eigene Art, um die Sachen zu packen.

class Kurztrip : Urlaub 
{
	public void SachenPacken() 
	{
		Console.WriteLine("Tasche nach Hamburg packen");
	}
}

class Strandurlaub : Urlaub
{
	public void SachenPacken()
	{
		Console.WriteLine("Koffer für Kenia packen");
	}
}

Um jetzt den Polymorphismus korrekt anzuwenden, müsste man folgendes schreiben:

Urlaub urlaub = new Kurztrip();
urlaub.SachenPacken();

Wir haben zwar einen Kurztrip geplant, aber das interessiert hier keinen. Es wird trotzdem die Methode aus dem Urlaub verwendet. Erst wenn man den Typen von Urlaub in Kurztrip ändert, wird die Tasche gepackt.

Wie könnte man das Problem umgehen?

Damit man die Kurztrip-Methode aufrufen kann, müssen in beiden Klassen noch zwei Schlüsselwörter definiert werden: virtual und override

class Urlaub
{
	public virtual void SachenPacken()
	{
		Console.WriteLine("Für den Urlaub Sachen packen");
	}
}

class Kurztrip : Urlaub
{
	public override void SachenPacken()
	{
		Console.WriteLine("Tasche nach Hamburg packen");
	}
}

Erst jetzt wird die Tasche gepackt und nicht nur die Sachen.

Eine weitere Möglichkeit wäre, direkt mit abstrakten Klassen zu Arbeiten.

Da es sich jedoch um abstrakte Klassen handelt, können wir natürlich keine Instanzen mehr davon erstellen.

Der Code wäre dann in etwa so:

abstract class Urlaub
{
	public abstract void SachenPacken();
}

class Kurztrip : Urlaub
{
	public override void SachenPacken()
	{
		Console.WriteLine("Tasche nach Hamburg packen");
	}
}

Das sieht doch schon viel besser aus, oder?

Ein weiterer Vorteil von abstrakten Klassen ist ja: Sie kann auch Logik beinhalten 🙂

Um in den Urlaub zu gelangen, müssen wir Losfahren (und natürlich auch ankommen).

abstract class Urlaub 
{
	public abstract void SachenPacken();

	public void Losfahren(IFahrzeug fahrzeug) 
	{
		fahrzeug.Einsteigen();
		fahrzeug.Losfahren();
		fahrzeug.Ankommen();
	}
}

Das führt mich schon auf das nächste Thema.

Polymorphismus mit Interfaces

Was bereits mit abstrakten Klassen funktioniert, funktioniert natürlich auch mit Interfaces.

Hier erstellen wir uns ebenfalls eine Struktur und definieren bereits ein paar Methoden:

interface IFahrzeug 
{
	void Einsteigen();
	void Losfahren();
	void Ankommen();
}

Und im Anschluss werden noch die passenden Klassen erstellt:

class Auto : IFahrzeug 
{
	public void Einsteigen()
	{
		Console.WriteLine("Tür auf und reinsetzen.");
	}
	
	public void Losfahren()
	{
		Console.WriteLine("Gang einlegen und Gas geben.");
	}
	
	public void Ankommen()
	{
		Console.WriteLine("Anhalten und aussteigen.");
	}
}

class Fahrrad : IFahrzeug
{
	public void Einsteigen()
	{
		Console.WriteLine("Festhalten und aufsteigen.");
	}
	
	public void Losfahren()
	{
		Console.WriteLine("Kräftig in die Pedale treten.");
	}
	
	public void Ankommen()
	{
		Console.WriteLine("Anhalten und absteigen.");
	}
}

Soweit so gut. Wir haben jetzt zwei Fahrzeuge. Einmal ein Auto und einmal ein Fahrrad.

Bei beiden Objekten kann man jetzt sagen, es ist ein Fahrzeug.

Jedes Auto ist ein Fahrzeug. Aber nicht jedes Fahrzeug ist ein Auto.

Polymorphie in der Praxis

Wer bis jetzt alles gelesen hat und sich gedacht hat:

Was hat das denn bitte mit Polymorphie zu tun?

Dem kann ich beruhigt sagen: nichts 🙂

Naja, das ist nur die halbe Wahrheit.

Fassen wir mal das bisher geschriebene zusammen und betrachten dieses Stückchen Quellcode:

Urlaub urlaub = new Strandurlaub();
urlaub.SachenPacken();

IFahrzeug auto = new Auto();
urlaub.Losfahren(auto);

Wir erstellen uns einen Urlaub (wenn es doch so einfach wäre :-)). Dabei spielt es absolut keine Rolle welchen. Es kann alles mögliche sein. In diesem Fall ist es ein Strandurlaub. Es könnte aber genauso gut auch ein Winterurlaub oder auch eine Städtereise sein.

Um in den Urlaub zu kommen, wird ein Fahrzeug benötigt. Hier spielt es wiederum keine Rolle, um welches Fahrzeug es sich handelt. Es könnte ein Auto sein, ein Fahrrad oder von mir aus auch ein Maulesel. Solange man sich darauf fortbewegen kann, ist alles erlaubt.

Doch Polymorphie ist eigentlich noch mehr als das.

Der Begriff bedeutet ja „Vielgestaltigkeit“. Heißt also, man könnte das oben erwähnte Fahrzeug immer wieder neu initialisieren. Beispielsweise so:

IFahrzeug fahrzeug = new Auto();
fahrzeug = new Fahrrad();
fahrzeug = new Maulesel();
fahrzeug = new Traktor();

Wenn alle diese Typen das Interface IFahrzeug implementieren, dann ist das ohne weiteres möglich.

Zugegeben, in der Praxis sieht man sowas gar nicht. Was man jedoch häufiger sieht, ist sowas hier:

IFahrzeug[] fahrzeuge = new IFahrzeug[4];
fahrzeuge[0] = new Auto();
fahrzeuge[1] = new Fahrrad();
fahrzeuge[2] = new Maulesel();
fahrzeuge[3] = new Traktor();

Man bündelt mehrere vermeidlich unterschiedliche Objekte in einem Array vom gleichen Typ.

Übrigens, die Polymorphie ist der Grundstein und die Basis des Strukturmusters „Composite„. Hier muss man tatsächlich mehrere Objekte vom unterschiedlichen Typus in einem Array vereinigen und anschließend auswerten.

Die 4 Arten der Polymorphie

In der Informatik unterscheiden wir zwischen vier verschiedenen Arten der Polymorphie. In der Regel verwenden wir das einfach, ohne es zu merken oder gar zu Wissen.

1. Überladung

Wenn du den Begriff Operatorüberladung kennst, dann weißt du auch, was mit dieser Polymorphie-Art anzufangen.

Ganz stupide gesagt, man verwendet mehrere Operatoren (z.B. das plus oder das mal) um Objekte zu manipulieren.

Ein Beispiel könnte etwa wie foglt aussehen:

Vector3D v1 = new Vector3D(1, 2, 3);
Vector3D v2 = new Vector3D(3, 2, 1);
Vector3D v3 = v1 + v2; // 4, 4, 4

2. Typumwandlung

Ähnlich wie die Überladung ist auch die Typumwandlung. Manchmal auch als Coercion bezeichnet.

Hier interagiert man jedoch zusätzlich mit verschiedenen Typen:

Vector3D v1 = new Vector3D(1, 2, 3);
Vector3D v2 = v1 * 2; // 2, 4, 6

In diese Kategorie fallen im Übrigen auch alle Arten von „casting“. Also einer expliziten Typumwandlung.

3. Parametrischer Polymorphismus

Der parametrische Polymorphismus hat – wie man vielleicht im ersten Augenblick vermuten würde – nichts mit den Parametern einer Methode zu tun.

Vielmehr handelt es sich hierbei um die sogenannten Generics.

Das wohl bekannteste Beispiel hierfür ist die Liste. Da die Liste ziemlich viele Typen aufnehmen kann, macht es dieses unscheinbare Objekt zum besten Beispiel des Polymorphismus.

Mehr Gestaltungsmöglichkeiten gibt es wohl kaum 🙂

4. Inklusionspolymorphismus

Ein schwieriges Wort für eigentlich ein ganz einfaches Prinzip. Viele Entwickler sagen auch einfach nur Subtyping oder auch Vererbung. Also eigentlich genau das, was ich oben bereits beschrieben habe.

Somit kann jede Methode, statt auf dem Subtyp auch auf dem Basistyp aufgerufen werden. Genauso wie in unserem Beispiel mit der Methode Losfahren.

Fazit – Polymorphismus

Fassen wir ganz kurz zusammen:

Polymorphie steht für Vielgestaltigkeit. Mit anderen Worten, man kann ein Objekt auf verschiedenen Wegen verwenden.

Dazu gehören:

  • Vererbung und die Verwendung der Basistypen bzw. Schnittstellen
  • Generische Klassen – oder auch Templates genannt – die auf unterschiedliche Objekte angewandt werden können.
  • Operatorüberladungen, die bekannte Operatoren auf unterschiedlichen Objekten ausführen können.
  • Casting (sowohl Upcast als auch Downcast) – welches uns erlaubt ein Objekt in ein konkreten während der Laufzeit umwandeln zu können.

Der wohl wichtigste von allem ist der Inklusionspolymorphismus.

Warum?

Weil es den eigenen Quellcode so flexibel macht und eigentlich die Basis für das ganze objektorientierte Programmierparadigma steht.

Kategorien:
Grundlagen
Das könnte dir auch gefallen
Sei der erste und teile deine Meinung mit der Welt!
... und was meinst du dazu?
Deine E-Mail-Adresse wird nicht veröffentlicht.