Menu
Coddy logo textTech

Interfaces implementieren

Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 41 von 61.

Nachdem du nun verstanden hast, was eine Schnittstelle ist – eine Struktur, die ausschließlich Funktionszeiger enthält –, ist es an der Zeit, konkrete Implementierungen zu erstellen, die diesen Vertrag erfüllen.

Erinnern wir uns an unsere ILogger-Schnittstelle aus der vorherigen Lektion:

typedef void (*LogFunc)(const char* message);

typedef struct {
    LogFunc log;
} ILogger;

Um diese Schnittstelle zu implementieren, schreiben wir tatsächliche Funktionen, die der Signatur von LogFunc entsprechen, und erstellen anschließend ILogger-Instanzen, denen diese Funktionen zugewiesen werden:

void console_log(const char* message) {
    printf("[CONSOLE] %s\n", message);
}

void file_log(const char* message) {
    printf("[FILE] %s\n", message);  // Simuliere Dateiausgabe
}

ILogger create_console_logger() {
    ILogger logger = { console_log };
    return logger;
}

ILogger create_file_logger() {
    ILogger logger = { file_log };
    return logger;
}

Jede „Konstruktor“-Funktion gibt ein ILogger mit einer anderen eingebundenen Funktion zurück. Code, der diese Logger verwendet, muss nicht wissen, welche Implementierung er erhalten hat:

void do_work(ILogger* logger) {
    logger->log("Starting work...");
    logger->log("Work complete!");
}

int main() {
    ILogger console = create_console_logger();
    ILogger file = create_file_logger();
    
    do_work(&console);  // Verwendet console_log
    do_work(&file);     // Verwendet file_log
    return 0;
}

Die Funktion do_work ist vollständig von der Protokollierungsimplementierung entkoppelt. Du kannst Protokollierer frei austauschen, ohne die Kernlogik zu ändern: Das ist die Stärke der Programmierung gegen eine Schnittstelle.

challenge icon

Aufgabe

Einfach

Erstellen wir ein INotifier-System, das veranschaulicht, wie verschiedene Implementierungen denselben Schnittstellenvertrag erfüllen können. Du wirst konkrete Benachrichtigungsdienste erstellen, einen EmailNotifier und einen SMSNotifier, die beide einer gemeinsamen Schnittstelle entsprechen, aber unterschiedliche Ausgaben erzeugen.

Du wirst deinen Code auf drei Dateien verteilen:

  • notifier.h: Definiere hier die Schnittstelle. Erstelle einen Funktionszeigertyp namens NotifyFunc, der eine const char*-Nachricht übernimmt und nichts zurückgibt. Definiere anschließend eine INotifier-Struktur, die ausschließlich einen notify-Funktionszeiger dieses Typs enthält. Deklariere außerdem zwei Konstruktorfunktionen: create_email_notifier und create_sms_notifier, die jeweils einen INotifier als Wert zurückgeben.
  • notifier.c: Implementiere hier die konkreten Benachrichtigungsfunktionen und Konstruktoren. Erstelle:
    • email_notify: Gibt die Nachricht im Format [EMAIL] message aus
    • sms_notify: Gibt die Nachricht im Format [SMS] message aus
    • create_email_notifier: Gibt einen mit INotifier verknüpften email_notify zurück
    • create_sms_notifier: Gibt einen mit INotifier verknüpften sms_notify zurück
  • main.c: Führe hier alles zusammen. Lies einen Benachrichtigungstyp und eine Nachricht ein, erstelle mithilfe der Konstruktorfunktionen den passenden Benachrichtigungsdienst und sende die Benachrichtigung über die Schnittstelle.

Dein Programm erhält zwei Eingaben: einen Benachrichtigungstyp (1 für E-Mail, 2 für SMS) und eine zu sendende Nachricht.

Verwende die Konstruktorfunktionen, um den passenden Benachrichtigungsdienst zu erstellen, und rufe anschließend notify über die Schnittstelle auf, um die Nachricht anzuzeigen.

Beispielausgabe, wenn der Typ 1 und die Nachricht Meeting at 3pm lautet:

[EMAIL] Meeting at 3pm

Beispielausgabe, wenn der Typ 2 und die Nachricht Your code shipped lautet:

[SMS] Your code shipped

Die Stärke dieses Musters besteht darin, dass main.c nicht wissen muss, wie die einzelnen Benachrichtigungsdienste intern funktionieren. Es ruft einfach die notify-Funktion der Schnittstelle auf, und die richtige Implementierung wird ausgeführt. Denke daran, Include-Guards in deiner Headerdatei zu verwenden.

Probier es selbst

#include <stdio.h>
#include "notifier.h"

int main() {
    int type;
    char message[256];
    
    // Lies den Benachrichtigungstyp (1 für E-Mail, 2 für SMS)
    scanf("%d", &type);
    getchar(); // Zeilenumbruch verbrauchen
    
    // Lies die Nachricht
    fgets(message, sizeof(message), stdin);
    // Entferne abschließenden Zeilenumbruch, falls vorhanden
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Erstelle den entsprechenden Notifier basierend auf dem Typ
    // Verwende create_email_notifier() für Typ 1
    // Verwende create_sms_notifier() für Typ 2
    
    // TODO: Rufe die notify-Funktion über die Schnittstelle auf
    // notifier.notify(message);
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C-Compiler