CodeGym /Kurse /JAVA 25 SELF /Polymorphie in der Praxis anwenden

Polymorphie in der Praxis anwenden

JAVA 25 SELF
Level 18 , Lektion 3
Verfügbar

1. Polymorphie in Kollektionen: Wozu wird sie benötigt?

Beginnen wir mit der Frage: „Wozu wird Polymorphie in realen Programmen überhaupt benötigt?“

Stell dir einen Zoo vor. Es gibt eine Basisklasse Animal sowie eine Menge von Unterklassen: Dog, Cat, Cow, Parrot und sogar Platypus (Schnabeltier, für Freunde des Exotischen). Jedes von ihnen kann einen Laut von sich geben (makeSound()), aber auf seine eigene Art.

Anstatt für jedes Tier ein separates Array anzulegen, deklarierst du ein Array oder eine Liste vom Typ Animal und legst dort beliebige Objekte ab:

Animal[] animals = {
    new Dog(),
    new Cat(),
    new Cow(),
    new Parrot()
};

Jetzt kannst du über dieses Array iterieren und makeSound() für jedes Element aufrufen:

for (Animal animal : animals) {
    animal.makeSound();
}

Magie! Jedes Objekt weiß selbst, welchen Laut es ausgeben soll, und du musst nicht eine Menge if- oder switch-Anweisungen schreiben.

Beispiel per Analogie

Es ist, als würdest du einer Gruppe von Tieren den Befehl „Gib Laut!“ geben, und jedes entscheidet selbst, was zu tun ist: Der Hund bellt, die Katze miaut, und die Kuh muht. Du spezifizierst nicht, wer wer ist – du rufst einfach dieselbe Methode auf.

2. Praktisches Beispiel: eine Mitarbeiterhierarchie

Machen wir ein praxisnäheres Beispiel (und näher an der künftigen Arbeit in IT). Stellen wir uns vor, es gibt ein Unternehmen mit verschiedenen Mitarbeitenden: Manager, Entwickler, Tester. Jede:r hat eine Methode work(), die jedoch unterschiedlich ausgeführt wird.

Deklaration der Basisklasse

public class Employee {
    public void work() {
        System.out.println("Der Mitarbeiter arbeitet...");
    }
}

Unterklassen

public class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("Der Manager leitet eine Besprechung.");
    }
}

public class Developer extends Employee {
    @Override
    public void work() {
        System.out.println("Der Entwickler schreibt Code.");
    }
}

public class Tester extends Employee {
    @Override
    public void work() {
        System.out.println("Der Tester sucht nach Fehlern.");
    }
}

Verwendung eines Arrays/einer Liste des Basistyps

public class CompanyDemo {
    public static void main(String[] args) {
        Employee[] team = {
            new Manager(),
            new Developer(),
            new Tester(),
            new Developer()
        };

        for (Employee e : team) {
            e.work(); // Die "richtige" Methodenversion wird für jedes Objekt aufgerufen
        }
    }
}

Ausgabe:

Der Manager leitet eine Besprechung.
Der Entwickler schreibt Code.
Der Tester sucht nach Fehlern.
Der Entwickler schreibt Code.

Welche Vorteile gibt es?

  • Du schreibst nicht jede Menge Prüfungen à la „Wenn es ein Developer ist – dann mach X“.
  • Einen neuen Mitarbeitenden hinzufügen (zum Beispiel Designer) – einfach eine neue Klasse erstellen und sie dem Array hinzufügen.
  • Der Code, der das Mitarbeiter-Array verwendet, ändert sich überhaupt nicht!

3. Vorteile der Polymorphie: Flexibilität und Erweiterbarkeit

Stellen wir uns vor, in deiner Firma taucht ein neuer Mitarbeitendentyp auf – Designer. Alles, was du tun musst, ist eine neue Klasse zu erstellen:

public class Designer extends Employee {
    @Override
    public void work() {
        System.out.println("Der Designer erstellt Layouts.");
    }
}

Jetzt kannst du den Designer dem Team hinzufügen:

Employee[] team = {
    new Manager(),
    new Developer(),
    new Tester(),
    new Designer()
};

Voilà! Das Programm arbeitet sofort korrekt mit dem neuen Mitarbeitendentyp, ohne auch nur eine Zeile in dem Code zu ändern, der das Array durchläuft und work() aufruft.

Das ist die Erweiterbarkeit: Dein Code lässt sich leicht an neue Objekttypen anpassen.

4. Einschränkungen der Polymorphie: die Kehrseite der Medaille

Leider hat jede Magie ihre Grenzen (und ihren Preis – wie in jedem RPG).

Nur die Methoden der Basisklasse sind verfügbar

Wenn du mit einer Variable vom Typ Employee arbeitest, kannst du nur die Methoden aufrufen, die in der Klasse Employee deklariert sind. Hat die Klasse Developer eine spezielle Methode writeCode(), kannst du sie nicht direkt aufrufen:

Employee e = new Developer();
// e.writeCode(); // Kompilierfehler: Eine solche Methode gibt es in Employee nicht!

Wenn du unbedingt eine spezifische Methode aufrufen willst, musst du eine Typumwandlung (Casting) vornehmen. Das ist jedoch ein äußerster Notfall. Wenn du häufig castest, solltest du das Klassendesign überdenken – die Basisklasse oder das Interface sollte die benötigte Methode enthalten.

if (e instanceof Developer) {
    Developer dev = (Developer) e;
    dev.writeCode();
}

Dann verlierst du jedoch die Universalität und Eleganz, für die das alles gedacht war. Entwirf die Basisklasse daher so, dass sie nur die Methoden enthält, die tatsächlich für alle Unterklassen nötig sind.

5. Praxis: eine Mitarbeiterhierarchie implementieren

Verbinden wir das Nützliche mit dem Angenehmen: Wir schreiben eine kleine Anwendung mit mehreren Mitarbeitendentypen und verwenden Polymorphie, um sie zu verarbeiten.

Schritt 1: Basisklasse und Unterklassen

// Employee.java
public class Employee {
    public void work() {
        System.out.println("Der Mitarbeiter arbeitet...");
    }
}

// Manager.java
public class Manager extends Employee {
    @Override
    public void work() {
        System.out.println("Der Manager leitet eine Besprechung.");
    }
}

// Developer.java
public class Developer extends Employee {
    @Override
    public void work() {
        System.out.println("Der Entwickler schreibt Code.");
    }
}

// Tester.java
public class Tester extends Employee {
    @Override
    public void work() {
        System.out.println("Der Tester sucht nach Fehlern.");
    }
}

Schritt 2: Hauptklasse

// CompanyDemo.java
public class CompanyDemo {
    public static void main(String[] args) {
        Employee[] team = {
            new Manager(),
            new Developer(),
            new Tester(),
            new Developer()
        };

        for (Employee e : team) {
            e.work();
        }
    }
}

Schritt 3: Erweiterbarkeit hinzufügen

Angenommen, in einem Monat kommt im Unternehmen ein neuer Mitarbeitender dazu – ein Designer. Alles, was nötig ist:

public class Designer extends Employee {
    @Override
    public void work() {
        System.out.println("Der Designer erstellt Layouts.");
    }
}

Das war’s – jetzt kannst du den Designer dem Team hinzufügen:

Employee[] team = {
    new Manager(),
    new Developer(),
    new Tester(),
    new Designer()
};

Fazit

Der gesamte zentrale Code (CompanyDemo) blieb unverändert! Das ist die Stärke der Polymorphie.

6. Typische Fehler beim Einsatz von Polymorphie

Fehler Nr. 1: Zugriff auf spezifische Methoden über eine Referenz des Basistyps erwarten.
Sehr oft versuchen Einsteiger, spezifische Methoden einer Unterklasse über eine Variable des Supertyps aufzurufen. Zum Beispiel:

Employee e = new Developer();
// e.writeCode(); // Fehler! Eine solche Methode ist in Employee nicht definiert.

Um eine spezifische Methode aufzurufen, musst du casten – dabei geht jedoch die Universalität verloren.

Fehler Nr. 2: Die Annotation @Override nicht verwenden.
Wenn du die Annotation vergisst, kannst du versehentlich eine neue Methode statt einer Überschreibung schreiben (z. B. dich im Namen vertun). Dann greift die Polymorphie nicht, und es wird die Version aus der Superklasse aufgerufen.

Fehler Nr. 3: Kein gemeinsames Interface.
Wenn die Basisklasse die benötigte Methode nicht enthält, ist Polymorphie nicht möglich. Wenn in Employee zum Beispiel keine Methode work() existiert, kann die Schleife über das Mitarbeitenden-Array diese Methode nicht für alle aufrufen.

Fehler Nr. 4: Verstoß gegen das Open/Closed-Prinzip.
Wenn du zum Hinzufügen eines neuen Mitarbeitendentypen den Code ändern musst, der das Array bzw. die Liste durchläuft, nutzt du Polymorphie nicht richtig.

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION