【问题标题】:C - How client can use/access more than one implementation?C - 客户端如何使用/访问多个实现?
【发布时间】:2017-01-11 14:10:07
【问题描述】:

Below(image) 是来自Linux/net/socket.c 源的模仿方法。

背景:

用这种方法实现List抽象的原因是在实现snmp库之前用同样的方法制作一个工作原型。 F 灵感来自 Linux/net/socket.c,其中任何一个协议族实现(如 net/ipv4/af_inet.cnet/unix/af_unix.c/..)在调用 socket() 接口 api 时可用

客户端调用socket() api,基于传递给socket() 接口api 的参数(AF_INET | AF_UNIX | AF_XYZ) 使用任何一个 协议族实现。

上述方法中,list.h提供List接口,代码如下,

/********************** list.h ********************/


#ifndef LIST_H /* Header guard */
#define LIST_H
#include"type.h"

/****************** Interface - start  ********/

 typedef struct List List;
 typedef enum {ARRAY_IMPL, LINKED_LIST_IMPL}ImplType;


 typedef int (*compareTo)(const void *, const void *);
 typedef bool (*isLess)(const void *, const void *);
 typedef bool (*isEqual)(const void *, const void *);

 List* createList(ImplType);
  void freeList(List*);
  void swim(List*, int, isLess);
  void sink(List*, int, isLess);
const  void* deleteMax(List*, isLess);
const  void* sortDeleteMax(List*);
   int getSize(List*);
const void* getItem(List*, const int);
 List* sortInsertItem(List*, const void*, compareTo);
  void insertItem(List*, const void*);
const  void* deleteItem(List*, int);
const  void* deleteLastItem(List*);
const  void* deleteFirstItem(List*);
   int lSearch(const void*, List*, size_t, compareTo);
   int bSearch(const void*, List*, size_t, compareTo);
  void callInsertionSort(List*, size_t, isLess);
  void callMergeSort(List*, size_t, isLess);
  void swap(List*, int, int);
/****************** Interface - end  ********/
#endif

实现(arrayImpl.o/linkListImpl.o)到可执行文件(a.out)的链接发生在链接器阶段。

virtualImplLayer.c 根据传递给createList() 接口api 的参数(ARRAY_IMPL | LINKED_LIST_IMPL) 选择任何一个 实现处理程序。此实现处理程序存储在handler 全局变量中,如下所示。 接口 api 的其余部分依赖于这个全局变量。

/*****************virtualImplLayer.c*************************/
#include "list/listHandler.h"

/*****Private symbol - start *****************/
static ListHandler * findListImplHandler(ImplType);
/*****Private symbol - end   *****************/


ListHandler *handler = NULL;
/***** User interface - start *************/
List* createList(ImplType implType){

  handler =  findListImplHandler(implType);

  if(handler != NULL){

    List *list = handler->createList();
    return list;
  }
  fprintf(stderr, "createList() - No implementation for this feature\n");
  return NULL;

}


void freeList(List *list){

    handler->freeList(list);
}


void swim(List *list, int parentIndex, isLess less){

    handler->swim(list, parentIndex, less);

}


void sink(List *list, int index, isLess less){

    handler->sink(list, index, less);
}


const void* deleteMax(List *list, isLess less){

    return handler->listDeleteMaxElement(list, less);
}


const void* sortDeleteMax(List *list){

    return handler->sortedListDeleteMaxElement(list);
}
int getSize(List *list){

    return handler->listGetSize(list);
}


const void* getItem(List *list, const int index){

    return handler->listGetItem(list, index);
}


List* sortInsertItem(List *list, const void *item, compareTo compare){

    return handler->sortedListInsertItem(list, item, compare);
}


void insertItem(List *list, const void *item){

    handler->listInsertItem(list, item);
}
const void* deleteItem(List *list, int listIndex){

    return handler->listDeleteItem(list, listIndex);
}


const void* deleteLastItem(List *list){

    return handler->listDeleteLastItem(list);
}


const void* deleteFirstItem(List *list){

    return handler->listDeleteFirstItem(list);
}


int lSearch(const void *key, List *list, size_t size, compareTo compare){

    return handler->linearSearch(key, list, size, compare);
}


int bSearch(const void *key, List *list, size_t size, compareTo compare){

    return handler->binarySearch(key, list, size, compare);
}
void callInsertionSort(List *list, size_t size, isLess less){

    handler->insertionSort(list, size, less);
}


void callMergeSort(List *list, size_t size, isLess less){

    handler->mergeSort(list, size, less);
}


void swap(List *list, int i, int j){

    handler->swap(list, i, j);
}

/***** User interface -end *************/

/*****Private symbol - start *****************/
static ListHandler * findListImplHandler(ImplType implType){

  ListHandler *implHandler = NULL;
  int handlerIndex = 0;
  while(listHandlers[handlerIndex] !=NULL){

    implHandler = listHandlers[handlerIndex];
    if( implHandler->canHandle(implType) ){
      return implHandler;
    }
    handlerIndex++;
  }
  return NULL;
}
/*****Private symbol - end *****************/

Linux/net/ipv4/af_inet.c,Linux/net/unix/af_unix.c 等实现在加载阶段通过覆盖实现中的_init() 运行时代码(比如af_inet.c)链接,如下所示,

static int __init inet_init(void){
  ....
  void)sock_register(&inet_family_ops);
  ....
}

谈到问题,在virtualImplLayer.c 中给定实现,客户端程序不能期望使用/访问多个 实现(arrayImpl.c/LinkListImpl.c),因为handler变量被覆盖


完整的工作示例是here,并给出了编译指令here

问题:

ImplType 仅传递给createList() 接口,在virtualImplLayer.c 中,如何避免覆盖全局变量handler,以利用多个实现?

【问题讨论】:

  • 完全没有全局变量 (virtualImplLayer.c)。让findListImplHandler 缓存结果以便于查找。在使用任何 1 个列表实现时,查找速度会很快。切换时会导致一次查找未命中。
  • 现在是一个挑剔的人,因为我认为你的问题很好。但是您确实需要处理minimal reproducible example 的“最小”方面。
  • @StoryTeller 更新了查询,包含工作示例的详细信息
  • 你的例子并不缺乏细节。恰恰相反。如果有人想真正理解你的问题,他们需要筛选很多不相关的细节(是的,你展示的大部分代码以及设计说明都是无关紧要的)。
  • @StoryTeller 好的。如果有不相关的详细信息,请编辑查询

标签: c coding-style refactoring


【解决方案1】:

删除全局的唯一方法是将一些类型信息存储在 List 本身中。

例如,您可以强制执行约定(通过考虑一点 OO,只要 C 促进它)。两个List 实现都必须包含以下struct 作为第一个成员

struct ListRtti {
  ListHandler *handler_;
  // Other relevent meta data you may want
};

所以

struct List {
  ListRtti rtti_;

  // Implementation details
};

现在,您可以从指向对象本身的指针中检索处理程序。由于第一个成员的地址保证是整个对象的地址:

((ListRtti*)list)->handler_;

专业版:

  • 处理程序始终是一个间接距离。
  • 用户可以根据自己的喜好混合和交换实现。

缺点:

  • 元数据需要为每个分配的对象提供额外的存储空间。
  • 这个演员阵容让人大跌眼镜。

【讨论】:

  • 所以,struct ListRtti 的实现细节应该只对virtualImplLayer.c 可见。 struct List的实现细节,不需要可见
  • @overexchange - 差不多。
  • socket() api 是否允许使用套接字库从单个客户端调用 socket(AF_INET,,)socket(AF_UNIX,,)
  • 我相应地更改了here 的代码并且它正在工作。谢谢!!
猜你喜欢
  • 1970-01-01
  • 2011-08-31
  • 2018-03-02
  • 2012-07-10
  • 1970-01-01
  • 2020-03-02
  • 2014-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多