Implementare le interfacce
Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 41 di 61.
Ora che hai capito cos'è un'interfaccia, una struct che contiene solo puntatori a funzione, è il momento di creare implementazioni concrete che rispettino quel contratto.
Ricorda la nostra interfaccia ILogger della lezione precedente:
typedef void (*LogFunc)(const char* message);
typedef struct {
LogFunc log;
} ILogger;Per implementare questa interfaccia, scriviamo funzioni effettive che corrispondono alla firma di LogFunc, poi creiamo istanze di ILogger assegnando loro queste funzioni:
void console_log(const char* message) {
printf("[CONSOLE] %s\n", message);
}
void file_log(const char* message) {
printf("[FILE] %s\n", message); // Simulazione dell'output su file
}
ILogger create_console_logger() {
ILogger logger = { console_log };
return logger;
}
ILogger create_file_logger() {
ILogger logger = { file_log };
return logger;
}Ogni funzione "costruttrice" restituisce un ILogger con una funzione diversa collegata. Il codice che usa questi logger non deve sapere quale implementazione ha ricevuto:
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); // Usa console_log
do_work(&file); // Usa file_log
return 0;
}La funzione do_work è completamente disaccoppiata dall’implementazione della registrazione. Puoi sostituire liberamente i logger senza modificare la logica di base: questo è il potere della programmazione basata su un’interfaccia.
Sfida
FacileCostruiamo un sistema INotifier che mostra come implementazioni diverse possano rispettare lo stesso contratto di interfaccia. Creerai notificatori concreti, un EmailNotifier e un SMSNotifier, conformi entrambi a un'interfaccia comune ma in grado di produrre output diversi.
Organizzerai il codice in tre file:
notifier.h: definisci qui l'interfaccia. Crea un tipo puntatore a funzione chiamatoNotifyFuncche accetta un messaggioconst char*e non restituisce nulla. Definisci poi una structINotifiercontenente solo un puntatore a funzionenotifydi questo tipo. Dichiara inoltre due funzioni costruttrici:create_email_notifierecreate_sms_notifier, ciascuna delle quali restituisce unINotifierper valore.notifier.c: implementa qui le funzioni concrete di notifica e le funzioni costruttrici. Crea:email_notify: stampa il messaggio nel formato:[EMAIL] messagesms_notify: stampa il messaggio nel formato:[SMS] messagecreate_email_notifier: restituisce unINotifiercollegato aemail_notifycreate_sms_notifier: restituisce unINotifiercollegato asms_notify
main.c: riunisci qui tutti gli elementi. Leggi un tipo di notifica e un messaggio, crea il notificatore appropriato usando le funzioni costruttrici e invia la notifica tramite l'interfaccia.
Il programma riceverà due input: un tipo di notifica (1 per email, 2 per SMS) e un messaggio da inviare.
Usa le funzioni costruttrici per creare il notificatore appropriato, poi chiama notify tramite l'interfaccia per visualizzare il messaggio.
Output di esempio quando il tipo è 1 e il messaggio è Meeting at 3pm:
[EMAIL] Meeting at 3pmOutput di esempio quando il tipo è 2 e il messaggio è Your code shipped:
[SMS] Your code shippedIl vantaggio di questo schema è che main.c non deve sapere come funziona internamente ciascun notificatore. Chiama semplicemente la funzione notify dell'interfaccia e viene eseguita l'implementazione corretta. Ricorda di usare le guardie di inclusione nel file header.
Provalo tu
#include <stdio.h>
#include "notifier.h"
int main() {
int type;
char message[256];
// Lee el tipo de notificación (1 para correo electrónico, 2 para SMS)
scanf("%d", &type);
getchar(); // consume el salto de línea
// Lee el mensaje
fgets(message, sizeof(message), stdin);
// Elimina el salto de línea final si está presente
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO: Crea el notificador adecuado según type
// Usa create_email_notifier() para type 1
// Usa create_sms_notifier() para type 2
// TODO: Llama a la función notify a través de la interfaz
// notifier.notify(message);
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Basi di programmazione modulare
File di intestazioneGuardie di inclusioneFile sorgenteFunzioni staticheRipasso: calcolatrice modulare4Incapsulamento
Il concetto di puntatori opachiDefinire struct opacheGetter e setterLa convalida nei setterRiepilogo: scatola segreta2Oggetti e metodi
Le struct come oggettiIl puntatore 'Self'Correttezza constPuntatore o valoreMetodi di supportoRiepilogo: gestore di punti5Progetto: Conto bancario semplice
Configurazione del progettoImplementazione del conto8Polimorfismo
Puntatori a funzione nelle structSimulare i metodiIl concetto di interfacciaImplementare le interfacceIterazione polimorficaRiepilogo: Greeter11Pattern di progettazione in C
Pattern SingletonPattern FactoryPattern IteratorRiepilogo: Factory di Logger3Ciclo di vita degli oggetti
Pattern del costruttorePattern del distruttoreInizializzazione sullo stackCopia profondaRiepilogo: wrapper di stringhe6Ereditarietà tramite composizione
Incorporamento delle structLa regola del primo membroAccesso ai membri della classe baseUpcastingRiepilogo: gerarchia di forme9Progetto: Disegnatore di forme
Panoramica del progettoImplementazione del cerchioImplementazione del rettangoloUtilizzo polimorficoContenitore di formeEsercitati da solo: Compilatore C online