Menu
CoddyTech

实现接口

本课属于 Coddy C 学习旅程的“面向对象编程”单元。第 41 课,共 61 课。

现在你已经了解了接口是什么,也就是只包含函数指针的结构体,接下来该创建具体实现来履行这份契约了。

回想一下我们在上一课中介绍的 ILogger 接口:

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

typedef struct {
    LogFunc log;
} ILogger;

要实现这个接口,我们需要编写符合 LogFunc 签名的实际函数,然后创建将这些函数赋给实例的 ILogger:

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

void file_log(const char* message) {
    printf("[FILE] %s\n", message);  // 模拟文件输出
}

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

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

每个“构造函数”函数都会返回一个接入了不同函数的 ILogger。使用这些日志记录器的代码不需要知道它收到的是哪种实现:

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);  // 使用 console_log
    do_work(&file);     // 使用 file_log
    return 0;
}

do_work 函数与日志实现完全解耦。你可以自由更换日志记录器,而无需更改任何核心逻辑:这就是面向接口编程的优势。

challenge icon

挑战

简单

我们来构建一个 INotifier 系统,展示不同的实现如何满足同一接口约定。你将创建两个具体的通知器:EmailNotifier 和 SMSNotifier。它们都遵循同一个接口,但会产生不同的输出。

你将把代码分成 3 个文件:

  • notifier.h:在这里定义接口。创建一个名为 NotifyFunc 的函数指针类型,它接收一条 const char* 消息,不返回任何内容。然后定义一个 INotifier 结构体,其中只包含一个此类型的 notify 函数指针。另外,声明两个构造函数:create_email_notifier 和 create_sms_notifier,它们都按值返回一个 INotifier。
  • notifier.c:在这里实现具体的通知函数和构造函数。创建:
    • email_notify:按以下格式输出消息:[EMAIL] message
    • sms_notify:按以下格式输出消息:[SMS] message
    • create_email_notifier:返回一个绑定到 email_notify 的 INotifier
    • create_sms_notifier:返回一个绑定到 sms_notify 的 INotifier
  • main.c:在这里整合所有内容。读取通知类型和消息,使用构造函数创建相应的通知器,然后通过接口发送通知。

你的程序会接收两个输入:一个通知类型(1 表示电子邮件,2 表示 SMS)和一条要发送的消息。

使用构造函数创建相应的通知器,然后通过接口调用 notify 来显示消息。

当类型为 1,消息为 Meeting at 3pm 时,输出示例:

[EMAIL] Meeting at 3pm

当类型为 2,消息为 Your code shipped 时,输出示例:

[SMS] Your code shipped

这种模式的优势在于,main.c 不需要了解每种通知器的内部工作方式。它只需调用接口的 notify 函数,就会执行正确的实现。记得在头文件中使用 include guard。

亲手试试

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

int main() {
    int type;
    char message[256];
    
    // 读取通知类型(1 表示邮件,2 表示短信)
    scanf("%d", &type);
    getchar(); // 读取并丢弃换行符
    
    // 读取消息
    fgets(message, sizeof(message), stdin);
    // 如果末尾有换行符,就将其删除
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: 根据 type 创建对应的通知器
    // type 为 1 时使用 create_email_notifier()
    // type 为 2 时使用 create_sms_notifier()
    
    // TODO: 通过接口调用 notify 函数
    // notifier.notify(message);
    
    return 0;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C 在线编译器