1. 从句柄到对象:C语言中的观察者模式实现
在嵌入式开发和系统级编程中,C语言因其高效性和接近硬件的特性而占据重要地位。当我们需要在C语言中实现对象间的通信机制时,观察者模式(Observer Pattern)提供了一种优雅的解决方案。不同于面向对象语言中的原生支持,在C语言中我们需要通过句柄(Handle)和事件链表(Event List)来模拟这一模式。
观察者模式的核心是建立一种"发布-订阅"关系,让对象(在C语言中通常表现为结构体)能够监听其他对象的状态变化。当被观察对象发生特定事件时,所有注册的观察者都会收到通知。这种机制在GUI事件处理、传感器数据监控等场景中尤为常见。
提示:虽然C语言没有类的概念,但通过结构体+函数指针的组合,完全可以实现类似面向对象的设计模式。关键在于如何组织数据结构和消息传递机制。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 观察者模式的核心组件设计
2.1 基础数据结构定义
首先我们需要定义几个核心数据结构:
c复制typedef void (*EventHandler)(void* sender, void* args);
typedef struct _ObserverNode {
EventHandler handler;
void* context; // 观察者上下文数据
struct _ObserverNode* next;
} ObserverNode;
typedef struct {
ObserverNode* head;
int count;
} EventList;
这里EventHandler是一个函数指针类型,定义了事件处理函数的签名。ObserverNode构成链表的基本节点,每个节点包含一个事件处理函数和上下文数据。EventList则管理整个观察者链表。
2.2 对象与句柄的映射关系
在纯C环境中,我们通常使用句柄来引用对象:
c复制typedef int ObjectHandle;
typedef struct {
EventList eventLists[MAX_EVENTS]; // 每个对象可以支持多种事件
// 其他对象属性...
} Object;
Object* objectPool[MAX_OBJECTS]; // 对象池
句柄实际上就是对象池数组的索引,这种间接访问提供了更好的封装性和安全性。当我们需要操作对象时,先通过句柄从对象池中获取实际的对象指针。
3. 事件链表的实现细节
3.1 基本链表操作
事件链表需要支持三种基本操作:添加观察者、移除观察者和触发事件。以下是典型实现:
c复制void AddObserver(EventList* list, EventHandler handler, void* context) {
ObserverNode* node = (ObserverNode*)malloc(sizeof(ObserverNode));
node->handler = handler;
node->context = context;
node->next = list->head;
list->head = node;
list->count++;
}
void RemoveObserver(EventList* list, EventHandler handler) {
ObserverNode** curr = &list->head;
while (*curr) {
if ((*curr)->handler == handler) {
ObserverNode* temp = *curr;
*curr = (*curr)->next;
free(temp);
list->count--;
break;
}
curr = &(*curr)->next;
}
}
void NotifyEvent(EventList* list, void* sender, void* args) {
ObserverNode* node = list->h
