基于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
相关产品推荐
相关产品推荐

