C 语言中的设计模式适配器

Design Pattern Adapter in C

提问人:Source 提问时间:10/27/2023 更新时间:10/28/2023 访问量:88

问:

定义

适配器是一种结构设计模式,它允许具有 不兼容的协作接口。

我必须使用不兼容的回调函数指针,第一个参数有所不同。

我们知道对象有键值对,数组有索引值对。char * 与 int。

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

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

用例

void process_object(void (*callback)(char *key, void *value)) {
    // callback if key-value-based properties
    callback(key, value);

    // callback for array-based properties
    callback((int)key, value); // trying to implement adapter pattern for this
}

我本来可以使用,但正在寻找一个基于适配器设计模式的优雅解决方案。void *

我的尝试

#include <stdio.h>

typedef struct Adapter {
    void (*obj)(char *key, void *value);
    void (*arr)(int index, void *value);
} Adapter;

void property_callback(char *key, void *value) {
    printf("%s: %s\n", key, value);
}

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

评论

0赞 n. m. could be an AI 10/27/2023
目前还不清楚你的问题是什么。您能展示一下您如何使用回调以及您希望如何使用它们吗?
0赞 Lundin 10/27/2023
怎么说得通?这个功能是什么?object_callbackindex
0赞 Source 10/27/2023
index 是数组中项的索引
0赞 Lundin 10/27/2023
什么阵列?代码中没有数组。我问的是,怎么知道这个变量的含义,它是一个全局变量吗?object_callbackindex

答:

1赞 Cem Polat 10/27/2023 #1

您需要创建一个适配器函数,该函数将弥合两个不同回调接口之间的差距。下面是将适配器函数与不同回调一起使用的简单示例。

#include <stdio.h>

// Define the original callback functions
void objectCallback(char *key, void *value) {
    printf("%s: %s\n", key, (char*)value);
}

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

// Adapter structure to encapsulate the original callbacks
typedef struct {
    void (*callback)(void* keyOrIndex, void *value);
} Adapter;

// Adapter function for objectCallback
void objectAdapter(void* key, void *value) {
    objectCallback((char*)key, value);
}

// Adapter function for arrayCallback
void arrayAdapter(void* key, void *value) {
    int idx = (int)(long)key; // Cast void pointer to int
    arrayCallback(idx, value);
}

int main() {
    // Create an adapter for objectCallback
    Adapter objectAdapterInstance = {objectAdapter};

    // Create an adapter for arrayCallback
    Adapter arrayAdapterInstance = {arrayAdapter};

    // Demonstrate the use of the adapters
    char* k = "property_key";
    char* v = "property_value";

    // Use the object adapter
    objectAdapterInstance.callback(k, v);

    // Use the array adapter
    int i = 123;
    arrayAdapterInstance.callback((void*)(long)i, v);

    return 0;
}

评论

0赞 Source 11/21/2023
我意识到最好的方法是使用单个方法,检查是否要调用数组版本,如果不是,则调用另一个对象版本。void *isdigit
0赞 Lundin 10/27/2023 #2

如果第一个参数没有,那么在编译时,您可以简单地使用该参数来区分这两种用途:void*

#include <stdio.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);
}


#define callback(a, b)                \
  _Generic((a),                       \
           char*:  object_callback,   \
           int:    array_callback     \
          ) (a,b)


int main (void)
{
    callback("hello", "world");
    callback(123, "world");
}

评论

0赞 Lundin 10/27/2023
这里需要注意的是,避免使用函数指针通常会导致更快的代码。具有函数指针的解决方案不太可能被编译器内联,这意味着开销执行时间。而我上面的代码很容易被编译器归结为两个 printf 调用。
0赞 Michael Walsh Pedersen 10/28/2023 #3

两种解决方案:

解决方案 1:删除回调函数指针的参数列表:

#include <stdio.h>

void property_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_object( void (*callback)(),
    int functype, char *key, int index, void *value) 
{
    if(functype==1) callback(key, value);
    if(functype==2) callback(index, value);
}

int main()
{
    process_object(property_callback , 1, "key", 123 , "value" ); 
    process_object(array_callback    , 2, "key", 123 , "value" );  
    return 0;
}

解决方案 2:使用回调指针的并集:

#include <stdio.h>

void property_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);
}

typedef union {
    void (*prop)(char *key, void *value); 
    void (*arr)(int index, void *value);
} cbtype;

void process_object( cbtype callback,
    int functype, char *key, int index, void *value) 
{
    if(functype==1) callback.prop(key, value);
    if(functype==2) callback.arr(index, value);
}

int main()
{
    process_object( (cbtype){.prop=property_callback} , 1, "key", 123 , "value" ); 
    process_object( (cbtype){.arr=array_callback}     , 2, "key", 123 , "value" );  
    return 0;
}