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.
Défi
FacileConstruisons 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éNotifyFuncqui prend un messageconst char*et ne renvoie rien. Définissez ensuite une structureINotifiercontenant uniquement un pointeur de fonctionnotifyde ce type. Déclarez également deux fonctions constructrices :create_email_notifieretcreate_sms_notifier, qui renvoient chacune unINotifierpar 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] messagesms_notify: affiche le message au format suivant :[SMS] messagecreate_email_notifier: renvoie unINotifierassocié àemail_notifycreate_sms_notifier: renvoie unINotifierassocié à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 3pmExemple de sortie lorsque le type est 2 et que le message est Your code shipped :
[SMS] Your code shippedL’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;
}
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
1Bases de la programmation modulaire
Fichiers d'en-têteGardes d'inclusionFichiers sourcesFonctions statiquesRécapitulatif : Calculatrice modulaire4Encapsulation
Concept des pointeurs opaquesDéfinir des structures opaquesGetters et settersValidation dans les settersRécapitulatif : La boîte secrète2Objets et méthodes
Structs comme objetsLe pointeur 'Self'Rigueur du mot-clé constPointeur vs ValeurMéthodes utilitairesRécapitulatif : Point Manager5Projet : Compte bancaire simple
Configuration du projetImplémentation du compte8Polymorphisme
Pointeurs de fonctions dans les structuresSimulation de méthodesLe concept d'interfaceImplémentation d'interfacesItération polymorphiqueRécapitulatif : Greeter11Patrons de conception en C
Patron SingletonPatron FabriquePatron ItérateurRécapitulatif : Logger Factory3Cycle de vie des objets
Pattern de constructeurPattern de destructeurInitialisation sur la pileCopie profondeRécapitulatif : String Wrapper6Héritage par composition
Imbrication de structLa règle du premier membreAccès aux membres parentsUpcastingRécapitulatif : Hiérarchie des formes9Projet : Dessinateur de formes
Aperçu du projetImplémentation du cercleImplémentation du rectangleUtilisation polymorpheConteneur de formesEntraînez-vous par vous-même : Compilateur C en ligne