下图(图片)是Linux/net/socket.c
源码的仿制方法。
Background:
Reason to implement
List
abstraction with this approach, is to make a working prototype before implementing snmp library, with same approach. f Inspired fromLinux/net/socket.c
, where any one of the protocol family implementations(likenet/ipv4/af_inet.c
ornet/unix/af_unix.c
/..) is available on invokingsocket()
interface apiClient invoking
socket()
api, avails any one protocol family implementation based on the argument(AF_INET
|AF_UNIX
|AF_XYZ
) passed tosocket()
interface api.
上述方法中,list.h
提供了List
接口(interface),代码如下,
/********************** 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()< 的参数 (
接口(interface) api。此实现处理程序存储在 ARRAY_IMPL | LINKED_LIST_IMPL
) 选择任何 实现处理handler
全局变量中,如下所示。 接口(interface) 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
变量被覆盖
问题:
ImplType
仅传递给 createList()
接口(interface),在 virtualImplLayer.c
中,如何避免覆盖全局变量 处理程序
,以利用多个实现?
最佳答案
删除全局的唯一方法是在 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_;
临:
- 处理程序始终是一个间接的距离。
- 用户可以根据自己的喜好混合和交换实现。
缺点:
- 元数据需要为每个分配的对象额外存储。
- Actor 阵容令人侧目。
关于C - 客户端如何使用/访问多个实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41593108/