Menu
CoddyTech

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 que contém 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 correspondam à 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 a saída para 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 associada. 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 está completamente desacoplada da implementação do registro em log. Você pode trocar os registradores à vontade sem alterar nenhuma parte da lógica principal: 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 que contenha apenas um ponteiro para 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: exibe a mensagem no formato: [EMAIL] message
    • sms_notify: exibe a mensagem no formato: [SMS] message
    • create_email_notifier: retorna um INotifier associado a email_notify
    • create_sms_notifier: retorna um INotifier associado 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 pela 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 pela 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

A vantagem 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 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(); // consuma o caractere de nova linha
    
    // Leia a mensagem
    fgets(message, sizeof(message), stdin);
    // Remova o caractere de nova linha no final, se houver
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Crie o notificador apropriado com base em type
    // Use create_email_notifier() para type 1
    // Use create_sms_notifier() para type 2
    
    // TODO: Chame a função notify por meio 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