Polymorphie
🚧 | Diese Seite befindet sich in Bearbeitung | 🚧 |
🤓 | Diese Seite ist eine Bewertungsrichtlinie, die ab Blatt 2 annotiert und ab Blatt 3 abgezogen wird. | 🤓 |
Beschreibung
Wenn wir von Polymorphie reden, sprechen wir vor allem von Vererbung von Klassen und Methoden. Also einem Kernbestandteil der Objektorientierten Programmierung.
Durch das Vererben von Eigenschaften an sogenannte "Kindklassen" verringern wir den Anteil an Code, den wir sonst mehrfach kopieren müssten. Auch ermöglicht dieses Vorgehen uns, verschiedene Eigenschaften von sonst ähnlichen Objekten schnell und unabhängig zu modellieren.
Gerne wird bei Polymorphie in der Objektorientierten Programmierung auf die Polymorphie in der Biologie verwiesen, da diese einem ähnlichem, wenn nicht sogar sehr gleichem Konzept folgt. Wir geben ein klassisches Beispiel:
class Animal {
void breathe();
abstract void speak();
}
class Cat extends Animal {
@Override
public void speak() {
System.out.println("Meow");
}
public void purr() {}
}
class Dog extends Animal {
@Override
public void speak() {
System.out.println("Bark");
}
public void fetch() {}
}
Schreiben wir die Klassen einmal in ein biologisches Äquivalent um:
Katzen und Hunde sind beides Tiere, teilen also schon einmal diese Eigenschaft. Auch können alle Tiere kommunizieren und atmen. Hunde und Katzen kommunizieren dabei aber unterschiedlich. Was Hunde und Katzen beide (in unserem Beispiel jetzt) nicht teilen, ist, dass Hunde gerne Bälle und Stöcke zurückbringen und Katzen schnurren.
Die Polymorphie entsteht also dadurch, dass wir verschiedene Tiere (Childclasses) mit jedoch auch gleichen Eigenschaften haben und diese mit einem Überbegriff (Parentclasses) darstellen können.
Warum den ganzen Aufwand? Wir können ja einfach die Klasse prüfen und entsprechend reagieren ... oder?
Schauen wir uns das mal in einem konkreten, überzugenden Beispiel an:
Negativbeispiel
class Cat{
public void speak() {}
public void purr() {}
}
class Dog{
public void speak() {}
public void fetch() {}
}
class Main {
public static void main(String[] args) {
Dog dog = new Dog();
speak(dog);
Cat cat = new Cat();
speak(cat);
}
public void speak(T animal) {
if (animal instanceOf Cat) {
System.out.println("Cat has spoken");
} else if (animal instanceOf Dog) {
System.out.println("Dog has spoken");
} else {
System.out.println("I don't know how that animal speaks");
}
}
}
Auch wenn das auf den ersten Blick "leicht" zu erweitern wäre und die gewollte Funktionalität implementiert, ist es viel komplizierter und fehleranfälliger als es eigentlich sein müsste.
Positivbeispiel
class Animal {
abstract void speak() {};
}
class Cat extends Animal {
@Override
public void speak() {}
public void purr() {}
}
class Dog extends Animal {
@Override
public void speak() {}
public void fetch() {}
}
class Main {
public static void main(String[] args) {
Animal[] animals = {new Dog(), new Cat()};
for (Animal animal : animals) {
animal.speak();
}
}
}
animal.speak()
kann hier keinen Fehler erzeugen, da die Methode in allen Klassen entsprechend definiert ist.