Menu
Coddy logo textTech

Implémentation d'interfaces

Fait partie de la section Programmation Orientée Objet du Journey C de Coddy. Leçon 41 sur 61.

Maintenant que vous comprenez ce qu’est une interface, une structure contenant uniquement des pointeurs de fonction, il est temps de créer des implémentations concrètes qui respectent ce contrat.

Rappelez-vous de notre interface ILogger de la leçon précédente :

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

typedef struct {
    LogFunc log;
} ILogger;

Pour implémenter cette interface, nous écrivons des fonctions réelles qui correspondent à la signature de LogFunc, puis créons des instances de ILogger auxquelles ces fonctions sont affectées :

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

void file_log(const char* message) {
    printf("[FILE] %s\n", message);  // Simulation de la sortie fichier
}

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

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

Chaque fonction « constructeur » renvoie un ILogger avec une fonction différente intégrée. Le code qui utilise ces enregistreurs n’a pas besoin de savoir quelle implémentation il a reçue :

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

La fonction do_work est complètement découplée de l’implémentation de la journalisation. Tu peux remplacer les enregistreurs librement sans modifier la logique principale : c’est là toute la puissance de la programmation basée sur une interface.

challenge icon

Défi

Facile

Construisons un système INotifier qui montre comment différentes implémentations peuvent respecter le même contrat d’interface. Vous allez créer des notificateurs concrets, EmailNotifier et SMSNotifier, qui se conforment tous deux à une interface commune, mais produisent des sorties différentes.

Vous allez organiser votre code sur trois fichiers :

  • notifier.h : définissez l’interface ici. Créez un type de pointeur de fonction appelé NotifyFunc qui prend un message const char* et ne renvoie rien. Définissez ensuite une structure INotifier contenant uniquement un pointeur de fonction notify de ce type. Déclarez également deux fonctions constructrices : create_email_notifier et create_sms_notifier, qui renvoient chacune un INotifier par valeur.
  • notifier.c : implémentez ici les fonctions de notification concrètes et les constructeurs. Créez :
    • email_notify : affiche le message au format suivant : [EMAIL] message
    • sms_notify : affiche le message au format suivant : [SMS] message
    • create_email_notifier : renvoie un INotifier associé à email_notify
    • create_sms_notifier : renvoie un INotifier associé à sms_notify
  • main.c : rassemblez tout ici. Lisez un type de notification et un message, créez le notificateur approprié à l’aide des fonctions constructrices, puis envoyez la notification via l’interface.

Votre programme recevra deux entrées : un type de notification (1 pour un e-mail, 2 pour un SMS) et un message à envoyer.

Utilisez les fonctions constructrices pour créer le notificateur approprié, puis appelez notify via l’interface afin d’afficher le message.

Exemple de sortie lorsque le type est 1 et que le message est Meeting at 3pm :

[EMAIL] Meeting at 3pm

Exemple de sortie lorsque le type est 2 et que le message est Your code shipped :

[SMS] Your code shipped

L’intérêt de ce modèle est que main.c n’a pas besoin de savoir comment fonctionne chaque notificateur en interne. Il appelle simplement la fonction notify de l’interface, et l’implémentation correcte s’exécute. N’oubliez pas d’utiliser des gardes d’inclusion dans votre fichier d’en-tête.

Essayez vous-même

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

int main() {
    int type;
    char message[256];
    
    // Lire le type de notification (1 pour email, 2 pour SMS)
    scanf("%d", &type);
    getchar(); // consommer le saut de ligne
    
    // Lire le message
    fgets(message, sizeof(message), stdin);
    // Supprimer le saut de ligne final s'il est présent
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Créer le notificateur approprié en fonction du type
    // Utiliser create_email_notifier() pour le type 1
    // Utiliser create_sms_notifier() pour le type 2
    
    // TODO: Appeler la fonction notify via l'interface
    // notifier.notify(message);
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur C en ligne