CodeGym /Kurse /C# SELF /Implementierung mehrerer Interfaces

Implementierung mehrerer Interfaces

C# SELF
Level 23 , Lektion 2
Verfügbar

1. Warum mehrere Interfaces implementieren?

Wenn du ein echtes System entwirfst, übernehmen Objekte oft nicht nur eine "Rolle" – sondern gleich mehrere. Stell dir vor: Du hast ein E-Book, das man nicht nur lesen, sondern auch bearbeiten und sogar in der Cloud speichern kann. Im objektorientierten Programmieren (OOP) bedeutet das, dass ein Objekt mehrere Interfaces implementieren muss:

  • IReadable – Lesen von Content.
  • IWritable – Bearbeiten von Content.
  • ISyncable – Synchronisation mit Remote-Speicher.

Genau hier kommt die Möglichkeit ins Spiel, mehrere Interfaces zu implementieren. Das ist eine Superkraft von C# (und OOP generell), die Klassen nicht haben: Du kannst nicht von mehreren Klassen erben, aber beliebig viele Interfaces implementieren.

Analogie aus dem echten Leben

Stell dir einen Mitarbeiter in einer Firma vor. John kann gleichzeitig sein:

  • Programmierer (schreibt Code)
  • Tester (prüft manchmal fremden Code)
  • Manager (plant Sprints oder die tägliche Kaffeedosis)

Diese "Rollen" haben komplett unterschiedliche Aufgaben. Aber John kommt mit jedem dieser Verträge klar! In der Programmierung ist es genauso: Eine Klasse implementiert Interfaces und übernimmt deren "Pflichten".

2. Syntax für die Implementierung mehrerer Interfaces

Ganz easy: Beim Deklarieren der Klasse listest du sie einfach mit Kommas getrennt auf:


public interface IReadable
{
    void Read();
}

public interface IWritable
{
    void Write(string text);
}

public class Note : IReadable, IWritable
{
    private string content = "";

    public void Read()
    {
        Console.WriteLine("Notiz: " + content);
    }

    public void Write(string text)
    {
        content = text;
        Console.WriteLine("Notiz aktualisiert!");
    }
}

In diesem Beispiel implementiert die Klasse Note beide Interfaces. Das heißt, sie muss beide Methoden implementieren: Read und Write.

3. Wie sieht das im Beispiel unserer App aus?

In unseren bisherigen Beispielen haben wir eine einfache Banking-App für Konten gebaut. Jetzt nehmen wir an: Wir brauchen eine universelle Klasse für ein Dokument, das man drucken (IPrintable), in eine Datei speichern (ISavable) und vielleicht per E-Mail verschicken kann (IEmailable).

Interfaces definieren:


public interface IPrintable
{
    void Print();
}

public interface ISavable
{
    void Save(string filePath);
}

public interface IEmailable
{
    void Email(string toAddress);
}

Klasse, die alles auf einmal kann:


public class Statement : IPrintable, ISavable, IEmailable
{
    public string Content { get; set; }

    public void Print()
    {
        Console.WriteLine("Drucke Kontoauszug...");
        Console.WriteLine(Content);
    }

    public void Save(string filePath)
    {
        // Wir nutzen File.WriteAllText aus der Standardbibliothek.
        File.WriteAllText(filePath, Content);
        Console.WriteLine($"Kontoauszug gespeichert in Datei: {filePath}");
    }

    public void Email(string toAddress)
    {
        Console.WriteLine($"Kontoauszug an E-Mail gesendet: {toAddress} (Simulation)");
    }
}

Jetzt kannst du diese Klasse im Code beliebig verwenden:


var stat = new Statement { Content = "Transaktionen im Monat: +1000 Einh., -500 Ausg." };
stat.Print();
stat.Save("statement.txt");
stat.Email("boss@bank.corp");

Übrigens: In der Praxis ist es sehr praktisch, so ein Objekt an Methoden zu übergeben, die ein bestimmtes Interface erwarten, ohne sich um die anderen Fähigkeiten zu kümmern. Zum Beispiel kann eine Druck-Methode einen IPrintable als Parameter nehmen, ohne zu wissen, dass das Objekt auch "Speicherer" und "Mailer" ist.

4. Verwendung von Interface-Referenzen: Wo sieht man, was mein Objekt kann?

Hier beginnt die Magie. Wenn du mehrere Interfaces implementiert hast, kannst du auf das Objekt nur als einen seiner Verträge zugreifen. Zum Beispiel:


IPrintable printable = new Statement { Content = "Vorlesung über Abstraktion" };
printable.Print(); // Nur drucken möglich

// printable.Save("file.txt"); // Fehler: Interface IPrintable kennt Save nicht.

Aber wenn wir auf ein anderes Interface wechseln:


ISavable savable = printable as ISavable;
if (savable != null)
{
    savable.Save("file.txt");
}

Das ist praktisch, wenn du ein Objekt an eine Methode übergibst, die eine Referenz auf ein bestimmtes Interface erwartet. So wird die Kopplung reduziert und der Code bleibt flexibel: Du kannst neue Implementierungen hinzufügen, ohne alten Code zu ändern.

5. Mehrfache Implementierung und gleiche Methoden in verschiedenen Interfaces

Jetzt wird's spannend! Was, wenn zwei Interfaces eine Methode mit gleichem Namen, aber unterschiedlicher Bedeutung verlangen? Zum Beispiel Interfaces für eine Kaffeemaschine:


public interface IStartable
{
    void Start();
}

public interface IRunnable
{
    void Start();
}

Die Kaffeemaschine kann sowohl "startbar" sein (IStartable – Start des Brühvorgangs), als auch "runnable" (IRunnable – Maschine geht in Betriebsmodus).

Standard-Implementierung (normal):


public class CoffeeMachine : IStartable, IRunnable
{
    public void Start()
    {
        Console.WriteLine("Kaffeemaschine startet für beide Rollen!");
    }
}

In diesem Fall deckt eine Implementierung von Start() beide Interfaces ab.

Was, wenn unterschiedliche Bedeutungen nötig sind?

Du kannst die explizite Interface-Implementierung nutzen:


public class CoffeeMachine : IStartable, IRunnable
{
    void IStartable.Start()
    {
        Console.WriteLine("Start: Getränkezubereitung begonnen!");
    }

    void IRunnable.Start()
    {
        Console.WriteLine("Start: Maschine in Betriebsmodus versetzt.");
    }
}

In diesem Fall kannst du die jeweilige Implementierung nur über eine Interface-Variable aufrufen:


CoffeeMachine cm = new CoffeeMachine();

IStartable startable = cm;
startable.Start(); // Start: Getränkezubereitung begonnen!

IRunnable runnable = cm;
runnable.Start(); // Start: Maschine in Betriebsmodus versetzt.

// cm.Start(); // Kompiliert nicht! Start ist als Klassenmethode nicht verfügbar.

Übrigens: Dieser Trick wird oft in der .NET-Standardbibliothek verwendet – zum Beispiel, wenn eine Klasse mehrere ähnliche Interfaces aus verschiedenen Frameworks implementiert und jedes sein eigenes Verhalten braucht.

6. Unterschied zwischen mehreren Interfaces und Vererbung

Möglichkeit Klasse (Vererbung) Interfaces
Anzahl Basistypen Nur einer Beliebig viele
Code-Vererbung Ja (Basisimplementierung möglich) Nein, nur Signaturen (außer Default-Methoden)
Zustand speichern Ja Nein
Neue Rolle hinzufügen Nein (oder schwierig, via Komposition) Easy, Interface implementieren
Besser für… "Physische" Hierarchien "Rollen"/logische Fähigkeiten

7. Praktische Anwendung: "Hybride" Objekte

Dank mehrfacher Interface-Implementierung kannst du Klassen mit einem einzigartigen Set an "Rollen" bauen, ohne überflüssige Vererbung.

Zum Beispiel in unserer Banking-App – du kannst eine Klasse machen, die Infos über sich speichern, sich selbst validieren und drucken kann – alles über verschiedene Interfaces:


public interface IValidatable
{
    bool Validate();
}

public class Check : IPrintable, ISavable, IValidatable
{
    public string Data { get; set; }

    public void Print()
    {
        Console.WriteLine("Check drucken: " + Data);
    }

    public void Save(string filePath)
    {
        File.WriteAllText(filePath, Data);
        Console.WriteLine("Check gespeichert: " + filePath);
    }

    public bool Validate()
    {
        return !string.IsNullOrEmpty(Data);
    }
}

So ein Ansatz ermöglicht es, leicht erweiterbare Architekturen zu bauen, in denen Klassen Rollen nach Bedarf kombinieren. Wenn du eine neue "Pflicht" brauchst – einfach ein neues Interface implementieren.

8. Typische Fehler und Stolpersteine

Ein häufiger Anfängerfehler: Vergessen, alle Interface-Mitglieder zu implementieren. Der Compiler verzeiht das nicht – es gibt einen Fehler und sagt dir, was fehlt. So einen Fehler erkennt man leicht: "Klasse muss Interface-Mitglied implementieren".

Das zweite häufige Problem – Verwirrung bei der Sichtbarkeit von Methoden. Wenn du eine Methode explizit implementierst, ist sie nicht über die Klassenvariable verfügbar – nur über das Interface.

Noch eine typische Situation – Refactoring: Du änderst ein Interface (z.B. Methode hinzugefügt), aber aktualisierst nicht alle Implementierungen. Das führt zu Compilerfehlern. Deshalb solltest du beim Design vermeiden, Interfaces zu ändern, wenn sie schon von vielen Klassen genutzt werden.

2
Aufgabe
C# SELF, Level 23, Lektion 2
Gesperrt
Implementierung einer einfachen Klasse für mehrere Interfaces
Implementierung einer einfachen Klasse für mehrere Interfaces
2
Aufgabe
C# SELF, Level 23, Lektion 2
Gesperrt
Verwendung von Interface-Referenzen
Verwendung von Interface-Referenzen
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION