OOP Dispatch: Dynamische Bindung, Single & Double Dispatch
Dieser Beitrag ist eine Begriffserklärung zum Dispatch in der objektorientierten Programmierung – inklusive Prüfungsfragen und Tags.
In a Nutshell
Dispatch bezeichnet die Auswahl der tatsächlich auszuführenden Methode zu einem Aufruf. Je nach Sprache und Konstrukt erfolgt die Bindung statisch zur Kompilierzeit oder dynamisch zur Laufzeit, Grundlage für Polymorphie.
Kompakte Fachbeschreibung
Unter Dispatch versteht man die Auflösung eines Methodenaufrufs auf eine konkrete Implementierung. Bei statischem Dispatch (Überladen) entscheidet der Compiler anhand der statischen Typen. Bei dynamischem Dispatch (Überschreiben) entscheidet die Laufzeitumgebung anhand des tatsächlichen Objekttyps, häufig über eine vtable.
Dispatch-Varianten:
- Single Dispatch: Auswahl basiert auf dem Empfängerobjekt
- Double Dispatch: Auswahl basiert auf zwei Laufzeittypen (Visitor Pattern)
- Multiple Dispatch: Auswahl basiert auf mehreren Laufzeitargumenten
Dynamische Bindung ermöglicht Polymorphie und das Open Closed Principle, setzt aber korrekte Verträge nach Liskov Substitution Principle voraus. Statischer Dispatch bietet Vorhersagbarkeit und Performance, dynamischer Dispatch bietet Flexibilität und Erweiterbarkeit.
Prüfungsrelevante Stichpunkte
- Statischer Dispatch: Überladen, Compilezeit-Entscheidung
- Dynamischer Dispatch: Überschreiben, Laufzeit-Entscheidung
- vtable: Dispatch-Tabelle für polymorphe Aufrufe
- Single Dispatch: Nur Empfängertyp entscheidet
- Double Dispatch: Empfänger und Parameter entscheiden
- Visitor Pattern: Implementiert Double Dispatch
- Performance: Statischer Dispatch schneller als dynamischer
- IHK-relevant: Abgrenzung Überladen vs Überschreiben
Kernkomponenten
- Virtual Method Table (vtable): Dispatch-Tabelle für polymorphe Methoden
- Single Dispatch: Standard-OOP-Dispatch-Mechanismus
- Double Dispatch: Visitor Pattern für komplexe Typbeziehungen
- Method Overriding: Dynamische Bindung bei Vererbung
- Method Overloading: Statische Bindung zur Compilezeit
- Runtime Type Information (RTTI): Typinformationen zur Laufzeit
- Dynamic Binding: Auflösung zur Laufzeit
- Static Binding: Auflösung zur Compilezeit
Praxisbeispiele
Single Dispatch (Standard OOP)
// Single Dispatch - nur der Empfängertyp entscheidet
abstract class Tier {
abstract void machGeraeusch();
}
class Hund extends Tier {
@Override
void machGeraeusch() {
System.out.println("Wuff!");
}
}
class Katze extends Tier {
@Override
void machGeraeusch() {
System.out.println("Miau!");
}
}
// Dynamische Bindung zur Laufzeit
Tier tier = new Hund(); // Statischer Typ: Tier, Dynamischer Typ: Hund
tier.machGeraeusch(); // Output: "Wuff!" (Single Dispatch)
Double Dispatch mit Visitor Pattern
// Double Dispatch - Empfänger und Parameter entscheiden
interface Tier {
void akzeptiere(Besucher besucher);
}
class Hund implements Tier {
@Override
public void akzeptiere(Besucher besucher) {
besucher.besuche(this); // Double Dispatch
}
}
class Katze implements Tier {
@Override
public void akzeptiere(Besucher besucher) {
besucher.besuche(this); // Double Dispatch
}
}
interface Besucher {
void besuche(Hund hund);
void besuche(Katze katze);
}
class Tierarzt implements Besucher {
@Override
public void besuche(Hund hund) {
System.out.println("Untersuche Hund: Impfung geben");
}
@Override
public void besuche(Katze katze) {
System.out.println("Untersuche Katze: Krallen schneiden");
}
}
// Verwendung
Tier[] tiere = {new Hund(), new Katze()};
Besucher tierarzt = new Tierarzt();
for (Tier tier : tiere) {
tier.akzeptiere(tierarzt); // Double Dispatch
}
// Output:
// Untersuche Hund: Impfung geben
// Untersuche Katze: Krallen schneiden
Statischer vs Dynamischer Dispatch
class Rechner {
// Statischer Dispatch (Overloading)
public int addiere(int a, int b) {
return a + b;
}
public double addiere(double a, double b) {
return a + b;
}
}
class PolymorpherRechner {
// Dynamischer Dispatch (Overriding)
public virtual int berechne(int a, int b) {
return a + b;
}
}
class Multiplizierer extends PolymorpherRechner {
@Override
public int berechne(int a, int b) {
return a * b;
}
}
// Statischer Dispatch zur Compilezeit
Rechner rechner = new Rechner();
int ergebnis1 = rechner.addiere(1, 2); // Compile: addiere(int, int)
// Dynamischer Dispatch zur Laufzeit
PolymorpherRechner poly = new Multiplizierer();
int ergebnis2 = poly.berechne(3, 4); // Runtime: Multiplizierer.berechne()
Vorteile und Nachteile
Vorteile von Dynamischem Dispatch
- Flexibilität: Laufzeit-Polymorphie ermöglicht erweiterbare Systeme
- Wartbarkeit: Neue Typen ohne Code-Änderung hinzufügen
- Abstraktion: Einheitliche Behandlung verschiedener Typen
- Open Closed Principle: Erweiterbar ohne Änderung
Nachteile
- Performance: Laufzeit-Overhead durch vtable-Lookup
- Komplexität: Schwerer zu verstehen und zu debuggen
- Speicher: Zusätzliche vtable-Strukturen
- Fehleranfälligkeit: Laufzeitfehler statt Compilezeitfehler
Dispatch-Mechanismen in verschiedenen Sprachen
Java
// Standard: Single Dispatch mit vtable
// Double Dispatch über Visitor Pattern
interface Shape {
double area();
void accept(Visitor visitor);
}
C++
// Direct Support: Multiple Dispatch
#include <boost/variant.hpp>
struct DoubleDispatcher {
void collide(Asteroid& a, Spaceship& s) { /* ... */ }
void collide(Spaceship& s, Asteroid& a) { /* ... */ }
};
Python
# Duck Typing: Dynamische Auflösung
class Animal:
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
return "Woof!"
# Dynamische Bindung zur Laufzeit
def animal_sound(animal):
return animal.make_sound() # Dispatch zur Laufzeit
Häufige Prüfungsfragen
-
Was ist der Unterschied zwischen Single und Double Dispatch? Single Dispatch berücksichtigt nur den Empfängertyp, Double Dispatch berücksichtigt Empfänger und Parametertypen.
-
Wie funktioniert eine vtable? Eine vtable ist ein Array von Funktionszeigern, das polymorphe Methodenaufrufe zur Laufzeit auflöst.
-
Wann verwendet man das Visitor Pattern? Wenn Operationen von der Datenstruktur getrennt werden müssen und Double Dispatch erforderlich ist.
-
Warum ist dynamischer Dispatch langsamer als statischer? Weil zur Laufzeit eine vtable-Lookup erforderlich ist statt direkter Methodenaufrufe zur Compilezeit.
Wichtigste Quellen
- https://de.wikipedia.org/wiki/Dynamische_Bindung
- https://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html
- https://refactoring.guru/de/design-patterns/visitor