Menu
Coddy logo textTech

Implementowanie interfejsów

Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 41 z 61.

Skoro już wiesz, czym jest interfejs — strukturą zawierającą wyłącznie wskaźniki do funkcji — czas utworzyć konkretne implementacje, które spełniają ten kontrakt.

Przypomnij sobie interfejs ILogger z poprzedniej lekcji:

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

typedef struct {
    LogFunc log;
} ILogger;

Aby zaimplementować ten interfejs, piszemy rzeczywiste funkcje zgodne z sygnaturą LogFunc, a następnie tworzymy instancje ILogger z przypisanymi do nich funkcjami:

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

void file_log(const char* message) {
    printf("[FILE] %s\n", message);  // Symulowanie wyjścia do pliku
}

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

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

Każda funkcja „konstruktora” zwraca ILogger z podłączoną inną funkcją. Kod korzystający z tych rejestratorów nie musi wiedzieć, którą implementację otrzymał:

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);  // Używa console_log
    do_work(&file);     // Używa file_log
    return 0;
}

Funkcja do_work jest całkowicie odseparowana od implementacji logowania. Możesz swobodnie zmieniać rejestratory bez modyfikowania jakiejkolwiek logiki podstawowej: na tym polega siła programowania zorientowanego na interfejs.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system INotifier, który pokazuje, jak różne implementacje mogą spełniać ten sam kontrakt interfejsu. Utworzysz konkretne powiadamiacze: EmailNotifier i SMSNotifier, które będą zgodne ze wspólnym interfejsem, ale będą generować różne wyniki.

Podzielisz kod na trzy pliki:

  • notifier.h: Zdefiniuj tutaj interfejs. Utwórz typ wskaźnika na funkcję o nazwie NotifyFunc, która przyjmuje wiadomość typu const char* i nic nie zwraca. Następnie zdefiniuj strukturę INotifier, zawierającą wyłącznie wskaźnik na funkcję notify tego typu. Zadeklaruj też dwie funkcje konstruktora: create_email_notifier i create_sms_notifier, z których każda zwraca wartość typu INotifier.
  • notifier.c: Zaimplementuj tutaj konkretne funkcje powiadomień i konstruktory. Utwórz:
    • email_notify: wyświetla wiadomość w formacie: [EMAIL] message
    • sms_notify: wyświetla wiadomość w formacie: [SMS] message
    • create_email_notifier: zwraca INotifier powiązany z email_notify
    • create_sms_notifier: zwraca INotifier powiązany z sms_notify
  • main.c: Połącz tutaj wszystkie elementy. Odczytaj typ powiadomienia i wiadomość, utwórz odpowiedni powiadamiacz za pomocą funkcji konstruktora i wyślij powiadomienie przez interfejs.

Program otrzyma dwa dane wejściowe: typ powiadomienia (1 dla emaila, 2 dla SMS-a) oraz wiadomość do wysłania.

Użyj funkcji konstruktora, aby utworzyć odpowiedni powiadamiacz, a następnie wywołaj notify przez interfejs, aby wyświetlić wiadomość.

Przykładowy wynik, gdy typ to 1, a wiadomość to Meeting at 3pm:

[EMAIL] Meeting at 3pm

Przykładowy wynik, gdy typ to 2, a wiadomość to Your code shipped:

[SMS] Your code shipped

Zaletą tego wzorca jest to, że main.c nie musi wiedzieć, jak każdy powiadamiacz działa wewnętrznie. Po prostu wywołuje funkcję interfejsu notify, a wykonuje się właściwa implementacja. Pamiętaj, aby użyć strażników dołączania w pliku nagłówkowym.

Spróbuj swoich sił

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

int main() {
    int type;
    char message[256];
    
    // Odczytaj typ powiadomienia (1 dla e-maila, 2 dla SMS-a)
    scanf("%d", &type);
    getchar(); // pobierz znak nowej linii
    
    // Odczytaj wiadomość
    fgets(message, sizeof(message), stdin);
    // Usuń końcowy znak nowej linii, jeśli występuje
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Utwórz odpowiedni obiekt powiadamiający na podstawie type
    // Użyj create_email_notifier() dla type 1
    // Użyj create_sms_notifier() dla type 2
    
    // TODO: Wywołaj funkcję notify przez interfejs
    // notifier.notify(message);
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C online