Menu
Coddy logo textTech

Implementando Interfaces

Parte da seção Programação Orientada a Objetos do Journey de C da Coddy. Lição 41 de 61.

Agora que você entende o que é uma interface, uma struct contendo apenas ponteiros para funções, é hora de criar implementações concretas que cumpram esse contrato.

Relembre nossa interface ILogger da lição anterior:

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

typedef struct {
    LogFunc log;
} ILogger;

Para implementar essa interface, escrevemos funções reais que correspondem à assinatura de LogFunc e, em seguida, criamos instâncias de ILogger com essas funções atribuídas:

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

void file_log(const char* message) {
    printf("[FILE] %s\n", message);  // Simulando saída de arquivo
}

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

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

Cada função "construtora" retorna um ILogger com uma função diferente conectada. O código que usa esses registradores não precisa saber qual implementação recebeu:

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;
}

A função do_work é completamente desacoplada da implementação de registro. Você pode trocar os registradores livremente sem alterar nenhuma lógica central: esse é o poder de programar para uma interface.

challenge icon

Desafio

Fácil

Vamos criar um sistema INotifier que demonstra como diferentes implementações podem cumprir o mesmo contrato de interface. Você criará notificadores concretos, um EmailNotifier e um SMSNotifier, que seguem uma interface comum, mas produzem saídas diferentes.

Você organizará seu código em três arquivos:

  • notifier.h: Defina a interface aqui. Crie um tipo de ponteiro para função chamado NotifyFunc que recebe uma mensagem const char* e não retorna nada. Em seguida, defina uma struct INotifier contendo apenas um ponteiro de função notify desse tipo. Declare também duas funções construtoras: create_email_notifier e create_sms_notifier, cada uma retornando um INotifier por valor.
  • notifier.c: Implemente aqui as funções concretas de notificação e as funções construtoras. Crie:
    • email_notify: imprime a mensagem no formato: [EMAIL] message
    • sms_notify: imprime a mensagem no formato: [SMS] message
    • create_email_notifier: retorna um INotifier conectado a email_notify
    • create_sms_notifier: retorna um INotifier conectado a sms_notify
  • main.c: Reúna tudo aqui. Leia um tipo de notificação e uma mensagem, crie o notificador apropriado usando as funções construtoras e envie a notificação por meio da interface.

Seu programa receberá duas entradas: um tipo de notificação (1 para e-mail, 2 para SMS) e uma mensagem a ser enviada.

Use as funções construtoras para criar o notificador apropriado e, em seguida, chame notify por meio da interface para exibir a mensagem.

Exemplo de saída quando o tipo é 1 e a mensagem é Meeting at 3pm:

[EMAIL] Meeting at 3pm

Exemplo de saída quando o tipo é 2 e a mensagem é Your code shipped:

[SMS] Your code shipped

O poder desse padrão é que main.c não precisa saber como cada notificador funciona internamente. Ele simplesmente chama a função notify da interface, e a implementação correta é executada. Lembre-se de usar guardas de inclusão no seu arquivo de cabeçalho.

Experimente você mesmo

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

int main() {
    int type;
    char message[256];
    
    // Leia o tipo de notificação (1 para email, 2 para SMS)
    scanf("%d", &type);
    getchar(); // consome a nova linha
    
    // Leia a mensagem
    fgets(message, sizeof(message), stdin);
    // Remove a nova linha final se presente
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Crie o notifier apropriado com base no tipo
    // Use create_email_notifier() para o tipo 1
    // Use create_sms_notifier() para o tipo 2
    
    // TODO: Chame a função notify através da interface
    // notifier.notify(message);
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de C online