You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于C语言的适配器设计模式:解决回调函数接口兼容问题

适配器模式解决C语言回调接口不兼容问题

问题描述

适配器模式是结构型设计模式,用于让接口不兼容的对象协作。当前存在两个回调函数,因第一个参数类型不兼容无法直接在同一场景使用:

  • 对象回调接收char*类型的键
  • 数组回调接收int类型的索引

原回调定义:

// 修正原代码的打印错误:应该输出key而非index
void object_callback(char *key, void *value) {
    printf("%s: %s\n", key, (char*)value);
}

void array_callback(int index, void *value) {
    printf("%d: %s\n", index, (char*)value);
}

使用场景中,process_object仅支持char*参数的回调,直接强转数组回调的参数会导致类型不匹配:

void process_object(void (*callback)(char *key, void *value)) {
    // 键值对回调逻辑正常
    callback(key, value);

    // 此处强转参数类型不合法,需要适配器解决
    callback((int)key, value); 
}

我们需要基于适配器模式实现优雅的兼容方案,而非直接使用void*。

解决方案

方案1:轻量包装式适配器

针对数组回调写一个适配函数,将char*类型的输入转换为int后调用原数组回调,适配成object_callback的接口格式:

#include <stdio.h>
#include <stdlib.h>

// 原回调函数
void object_callback(char *key, void *value) {
    printf("%s: %s\n", key, (char*)value);
}

void array_callback(int index, void *value) {
    printf("%d: %s\n", index, (char*)value);
}

// 数组回调的适配器函数
void array_callback_adapter(char *key_str, void *value) {
    // 场景1:输入是字符串形式的索引(如"0"、"1")
    int index = atoi(key_str);
    // 场景2:输入是直接传递的索引指针(需确保类型安全)
    // int index = *(int*)(key_str);
    array_callback(index, value);
}

// 使用场景
void process_object(void (*callback)(char *key, void *value), char *key_or_index, void *value) {
    callback(key_or_index, value);
}

int main() {
    char *obj_key = "username";
    char *arr_index_str = "2";
    char *value = "Bob";

    // 处理对象属性
    process_object(object_callback, obj_key, value);
    // 处理数组元素,通过适配器兼容接口
    process_object(array_callback_adapter, arr_index_str, value);

    return 0;
}

方案2:通用结构体适配器

如果需要动态切换回调类型,可以用结构体封装适配器,提供统一的调用入口:

#include <stdio.h>
#include <stdint.h>

// 回调类型枚举
typedef enum {
    CALLBACK_OBJECT,
    CALLBACK_ARRAY
} CallbackType;

// 适配器结构体:封装回调类型与对应函数
typedef struct {
    CallbackType type;
    union {
        void (*obj_cb)(char*, void*);
        void (*arr_cb)(int, void*);
    } cb;
} CallbackAdapter;

// 统一调用入口
void adapter_invoke(CallbackAdapter *adapter, void *key_or_index, void *value) {
    switch (adapter->type) {
        case CALLBACK_OBJECT:
            adapter->cb.obj_cb((char*)key_or_index, value);
            break;
        case CALLBACK_ARRAY:
            // 用intptr_t保证64位系统下指针转整数的安全性
            adapter->cb.arr_cb((int)(intptr_t)key_or_index, value);
            break;
        default:
            break;
    }
}

// 原回调函数
void object_callback(char *key, void *value) {
    printf("%s: %s\n", key, (char*)value);
}

void array_callback(int index, void *value) {
    printf("%d: %s\n", index, (char*)value);
}

// 使用场景
void process_data(CallbackAdapter *adapter, void *key_or_index, void *value) {
    adapter_invoke(adapter, key_or_index, value);
}

int main() {
    CallbackAdapter obj_adapter = {
        .type = CALLBACK_OBJECT,
        .cb.obj_cb = object_callback
    };

    CallbackAdapter arr_adapter = {
        .type = CALLBACK_ARRAY,
        .cb.arr_cb = array_callback
    };

    char *obj_key = "email";
    int arr_index = 1;
    char *value = "bob@example.com";

    // 处理对象
    process_data(&obj_adapter, obj_key, value);
    // 处理数组
    process_data(&arr_adapter, (void*)(intptr_t)arr_index, value);

    return 0;
}

方案说明

  • 方案1适合单一适配场景,代码轻量,无需额外结构体,直接通过包装函数完成接口转换。
  • 方案2适合需要动态切换回调类型的场景,扩展性更强,通过枚举和联合体封装不同类型的回调。
  • 注意参数转换的合法性:整数转指针需用intptr_t避免64位系统下的截断问题;字符串转整数需保证输入格式合法。

内容的提问来源于stack exchange,提问作者Source

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 12:16:14