Abstrakte Klassen und Interfaces

Abstraktion in der OOP

Abstraktion ist eines der vier Grundprinzipien der objektorientierten Programmierung (neben Kapselung, Vererbung und Polymorphismus). Sie ermöglicht es, gemeinsame Eigenschaften und Verhaltensweisen in übergeordneten Klassen oder Schnittstellen zu definieren, ohne eine konkrete Implementierung vorzugeben. Dadurch können verschiedene Unterklassen die gleiche Schnittstelle nutzen, aber unterschiedliches Verhalten zeigen.

Abstrakte Klassen

Eine abstrakte Klasse ist eine Klasse, die nicht direkt instanziiert werden kann. Sie dient als Basisklasse (Oberklasse) und kann sowohl abstrakte Methoden (ohne Implementierung) als auch konkrete Methoden (mit Implementierung) enthalten.

// Java-Beispiel
abstract class Fahrzeug {
    protected String marke;

    public Fahrzeug(String marke) {
        this.marke = marke;
    }

    // Abstrakte Methode - MUSS überschrieben werden
    abstract void beschleunigen();

    // Konkrete Methode - KANN überschrieben werden
    public String getMarke() {
        return this.marke;
    }
}

class Auto extends Fahrzeug {
    public Auto(String marke) {
        super(marke);
    }

    @Override
    void beschleunigen() {
        System.out.println(marke + " beschleunigt mit Motor.");
    }
}

class Fahrrad extends Fahrzeug {
    public Fahrrad(String marke) {
        super(marke);
    }

    @Override
    void beschleunigen() {
        System.out.println(marke + ": Fahrer tritt in die Pedale.");
    }
}

Merkmale abstrakter Klassen: Sie können Instanzvariablen, Konstruktoren, konkrete und abstrakte Methoden besitzen. Eine Unterklasse muss alle abstrakten Methoden implementieren, sofern sie selbst nicht abstrakt ist.

Interfaces (Schnittstellen)

Ein Interface definiert einen Vertrag: Es legt fest, welche Methoden eine Klasse bereitstellen muss, aber nicht wie. Seit Java 8 können Interfaces auch Default-Methoden mit Implementierung enthalten.

// Java-Beispiel
interface Fahrbar {
    void fahren();          // abstrakt (implizit)
    void bremsen();         // abstrakt

    // Default-Methode (seit Java 8)
    default void hupen() {
        System.out.println("Huuup!");
    }
}

interface Elektrisch {
    void laden();
}

// Eine Klasse kann MEHRERE Interfaces implementieren
class Elektroauto extends Fahrzeug implements Fahrbar, Elektrisch {
    public Elektroauto(String marke) {
        super(marke);
    }

    @Override void beschleunigen() { /* ... */ }
    @Override public void fahren()  { /* ... */ }
    @Override public void bremsen() { /* ... */ }
    @Override public void laden()   { /* ... */ }
}
Vergleich: Abstrakte Klasse vs. Interface
  • Vererbung: Eine Klasse kann nur eine abstrakte Klasse erweitern (Einfachvererbung), aber mehrere Interfaces implementieren.
  • Zustand: Abstrakte Klassen können Instanzvariablen und Konstruktoren besitzen. Interfaces können nur Konstanten (static final) deklarieren.
  • Methoden: Abstrakte Klassen dürfen konkrete und abstrakte Methoden haben. Interfaces haben standardmäßig abstrakte Methoden (seit Java 8 auch default/static).
  • Verwendung: Abstrakte Klassen für „ist-ein“-Beziehungen (z. B. Auto ist ein Fahrzeug). Interfaces für „kann“-Fähigkeiten (z. B. Auto kann fahren).
Polymorphismus

Polymorphismus (Vielgestaltigkeit) ermöglicht, dass eine Variable vom Typ der Oberklasse oder des Interfaces auf Objekte verschiedener Unterklassen verweisen kann. Zur Laufzeit wird die richtige Methode aufgerufen (dynamische Bindung):

Fahrzeug[] fuhrpark = {
    new Auto("BMW"),
    new Fahrrad("Canyon"),
    new Elektroauto("Tesla")
};

for (Fahrzeug f : fuhrpark) {
    f.beschleunigen();  // Ruft jeweils die spezifische Methode auf
}

Der Compiler kennt nur den statischen Typ (Fahrzeug), aber zur Laufzeit wird die Methode des dynamischen Typs (Auto, Fahrrad, Elektroauto) ausgeführt.

Design Patterns – Grundlagen

Design Patterns (Entwurfsmuster) sind bewährte Lösungsschablonen für wiederkehrende Probleme im Software-Design. Abstrakte Klassen und Interfaces spielen dabei eine zentrale Rolle:

  • Strategy Pattern: Ein Interface definiert eine Familie von Algorithmen. Verschiedene Klassen implementieren das Interface und stellen unterschiedliche Strategien bereit. Beispiel: verschiedene Sortieralgorithmen hinter einem gemeinsamen Interface Sortierer.
  • Template Method Pattern: Eine abstrakte Klasse definiert das Grundgerüst eines Algorithmus. Unterklassen überschreiben einzelne Schritte. Beispiel: eine abstrakte Klasse Datenexport mit der Template-Methode exportiere().
  • Observer Pattern: Ein Interface Beobachter wird von allen Klassen implementiert, die auf Änderungen reagieren wollen.

Abitur-Tipp: Im Abitur wird häufig verlangt, UML-Klassendiagramme zu lesen und zu erstellen, die abstrakte Klassen (kursiver Name) und Interfaces («interface») enthalten. Präge dir die Unterschiede ein: abstrakte Klasse = „ist-ein“-Beziehung mit geteiltem Code; Interface = „kann“-Fähigkeit mit Mehrfachvererbung. Typische Aufgabe: Modelliere eine Hierarchie und begründe, warum du abstrakte Klasse oder Interface gewählt hast.