Menu
Coddy logo textTech

Implementando interfaces

Parte de la sección Programación Orientada a Objetos del Journey de C de Coddy. Lección 41 de 61.

Ahora que entiendes qué es una interfaz, una estructura que contiene únicamente punteros a funciones, es hora de crear implementaciones concretas que cumplan ese contrato.

Recuerda nuestra interfaz ILogger de la lección anterior:

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

typedef struct {
    LogFunc log;
} ILogger;

Para implementar esta interfaz, escribimos funciones reales que coincidan con la firma de LogFunc y después creamos instancias de ILogger con esas funciones asignadas:

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

void file_log(const char* message) {
    printf("[FILE] %s\n", message);  // Simulando la salida a archivo
}

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

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

Cada función «constructor» devuelve un ILogger con una función diferente conectada. El código que utiliza estos registradores no necesita saber qué implementación recibió:

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 función do_work está completamente desacoplada de la implementación de registro. Puedes cambiar los registradores libremente sin modificar ninguna de las lógicas principales: ese es el poder de programar hacia una interfaz.

challenge icon

Desafío

Fácil

Construyamos un sistema INotifier que demuestre cómo distintas implementaciones pueden cumplir el mismo contrato de interfaz. Crearás notificadores concretos, EmailNotifier y SMSNotifier, que se ajustan a una interfaz común, pero producen salidas diferentes.

Organizarás tu código en tres archivos:

  • notifier.h: Define aquí la interfaz. Crea un tipo de puntero a función llamado NotifyFunc que reciba un mensaje const char* y no devuelva nada. Después, define una estructura INotifier que contenga únicamente un puntero a función notify de este tipo. Declara también dos funciones constructoras: create_email_notifier y create_sms_notifier, cada una de las cuales devuelve un INotifier por valor.
  • notifier.c: Implementa aquí las funciones de notificación concretas y las funciones constructoras. Crea:
    • email_notify: imprime el mensaje con el formato: [EMAIL] message
    • sms_notify: imprime el mensaje con el formato: [SMS] message
    • create_email_notifier: devuelve un INotifier conectado a email_notify
    • create_sms_notifier: devuelve un INotifier conectado a sms_notify
  • main.c: Reúne aquí todos los elementos. Lee un tipo de notificación y un mensaje, crea el notificador apropiado mediante las funciones constructoras y envía la notificación a través de la interfaz.

Tu programa recibirá dos entradas: un tipo de notificación (1 para correo electrónico, 2 para SMS) y un mensaje que enviar.

Usa las funciones constructoras para crear el notificador apropiado y después llama a notify a través de la interfaz para mostrar el mensaje.

Salida de ejemplo cuando el tipo es 1 y el mensaje es Meeting at 3pm:

[EMAIL] Meeting at 3pm

Salida de ejemplo cuando el tipo es 2 y el mensaje es Your code shipped:

[SMS] Your code shipped

La ventaja de este patrón es que main.c no necesita saber cómo funciona internamente cada notificador. Simplemente llama a la función notify de la interfaz y se ejecuta la implementación correcta. Recuerda usar protectores de inclusión en tu archivo de encabezado.

Pruébalo tú mismo

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

int main() {
    int type;
    char message[256];
    
    // Lee el tipo de notificación (1 para email, 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 apropiado según el tipo
    // Usa create_email_notifier() para el tipo 1
    // Usa create_sms_notifier() para el tipo 2
    
    // TODO: Llama a la función notify a través de la interfaz
    // notifier.notify(message);
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de C online