观察者模式指南:事件驱动的优雅实现

📖 你有没有遇到过这些问题?

想象一下这些生活场景:

场景1:新闻订阅

方式A:每天主动打电话问每个朋友"有什么新闻吗?"
方式B:订阅新闻推送,有新闻时自动收到通知

哪种方式更高效?

场景2:股票监控

方式A:不停地刷新股票软件查看价格变化
方式B:设置价格提醒,达到目标价格时自动通知

哪种方式更智能?

在编程中,观察者模式就像新闻订阅和股票提醒一样重要!

轮询检查像不停打电话询问一样低效:

// ❌ 轮询方式,效率低下
void main_loop(void)
{
    while (1)
    {
        // 不停地检查各种状态
        if (sensor_data_changed())
        {
            update_display();
            send_to_comm();
            check_alarm_conditions();
        }
        
        if (button_pressed())
        {
            update_menu();
            refresh_display();
        }
        
        if (timer_expired())
        {
            save_data();
            reset_timer();
        }
        
        // 浪费CPU资源不停轮询
        delay_ms(10);
    }
}

观察者模式像智能通知一样高效:

// ✅ 观察者模式,事件驱动
void sensor_data_ready_handler(const SensorData_t *data)
{
    // 传感器数据就绪时自动调用
    DisplayModule_UpdateData(data);
    CommModule_SendData(data);
    AlarmModule_CheckThresholds(data);
}

void button_press_handler(ButtonEvent_t event)
{
    // 按键按下时自动调用
    MenuModule_ProcessInput(event);
    DisplayModule_Refresh();
}

void setup_observers(void)
{
    // 注册观察者
    SensorModule_AddObserver(sensor_data_ready_handler);
    ButtonModule_AddObserver(button_press_handler);
}

本文将详细介绍观察者模式的原理和最佳实践,帮助开发者构建高效的事件驱动系统。


🎯 为什么需要观察者模式?

生活中的例子

场景1:微信群通知

传统方式:每个人定时问群主"有新消息吗?"
观察者模式:有新消息时群主自动@所有人

场景2:火警系统

传统方式:保安每隔几分钟巡查一遍所有房间
观察者模式:烟雾探测器检测到火情时自动报警

观察者模式的价值

  1. 降低耦合度:发布者不需要知道具体的订阅者
  2. 提高响应性:事件发生时立即通知,无延迟
  3. 节省资源:避免无效的轮询检查
  4. 易于扩展:新增观察者不影响现有代码

🌟 观察者模式基本结构

1. 核心组件

主题(Subject)和观察者(Observer)
// 观察者接口定义
typedef void (*EventHandler_t)(const void *event_data, void *user_data);

// 观察者结构
typedef struct Observer
{
    EventHandler_t handler;         // 事件处理函数
    void *user_data;                // 用户数据
    struct Observer *next;          // 链表指针
} Observer_t;

// 主题结构
typedef struct Subject
{
    Observer_t *observers;          // 观察者链表
    const char *name;               // 主题名称
    uint32_t observer_count;        // 观察者数量
} Subject_t;

// 主题操作接口
bool Subject_Init(Subject_t *subject, const char *name);
bool Subject_AddObserver(Subject_t *subject, EventHandler_t handler, void *user_data);
bool Subject_RemoveObserver(Subject_t *subject, EventHandler_t handler);
void Subject_NotifyObservers(Subject_t *subject, const void *event_data);
void Subject_Cleanup(Subject_t *subject);

2. 基础实现

观察者管理核心代码
// subject.c - 观察者模式核心实现

#include "observer_pattern.h"
#include <stdlib.h>
#include <string.h>

/**
 * @brief 初始化主题
 * @param subject 主题对象
 * @param name 主题名称
 * @return 初始化结果
 */
bool Subject_Init(Subject_t *subject, const char *name)
{
    if (subject == NULL)
    {
        return false;
    }
    
    subject->observers = NULL;
    subject->name = name;
    subject->observer_count = 0;
    
    return true;
}

/**
 * @brief 添加观察者
 * @param subject 主题对象
 * @param handler 事件处理函数
 * @param user_data 用户数据
 * @return 添加结果
 */
bool Subject_AddObserver(Subject_t *subject, EventHandler_t handler, void *user_data)
{
    if (subject == NULL || handler == NULL)
    {
        return false;
    }
    
    // 检查是否已存在
    Observer_t *current = subject->observers;
    while (current != NULL)
    {
        if (current->handler == handler && current->user_data == user_data)
        {
            return false; // 已存在
        }
        current = current->next;
    }
    
    // 创建新观察者
    Observer_t *new_observer = (Observer_t*)malloc(sizeof(Observer_t));
    if (new_observer == NULL)
    {
        return false;
    }
    
    new_observer->handler = handler;
    new_observer->user_data = user_data;
    new_observer->next = subject->observers;
    subject->observers = new_observer;
    subject->observer_count++;
    
    return true;
}

/**
 * @brief 移除观察者
 * @param subject 主题对象
 * @param handler 事件处理函数
 * @return 移除结果
 */
bool Subject_RemoveObserver(Subject_t *subject, EventHandler_t handler)
{
    if (subject == NULL || handler == NULL)
    {
        return false;
    }
    
    Observer_t **current = &subject->observers;
    
    while (*current != NULL)
    {
        if ((*current)->handler == handler)
        {
            Observer_t *to_remove = *current;
            *current = (*current)->next;
            free(to_remove);
            subject->observer_count--;
            return true;
        }
        current = &(*current)->next;
    }
    
    return false; // 未找到
}

/**
 * @brief 通知所有观察者
 * @param subject 主题对象
 * @param event_data 事件数据
 */
void Subject_NotifyObservers(Subject_t *subject, const void *event_data)
{
    if (subject == NULL)
    {
        return;
    }
    
    Observer_t *current = subject->observers;
    while (current != NULL)
    {
        if (current->handler != NULL)
        {
            current->handler(event_data, current->user_data);
        }
        current = current->next;
    }
}

/**
 * @brief 清理主题资源
 * @param subject 主题对象
 */
void Subject_Cleanup(Subject_t *subject)
{
    if (subject == NULL)
    {
        return;
    }
    
    Observer_t *current = subject->observers;
    while (current != NULL)
    {
        Observer_t *next = current->next;
        free(current);
        current = next;
    }
    
    subject->observers = NULL;
    subject->observer_count = 0;
}

3. 类型安全的观察者

强类型事件系统
// typed_observer.h - 类型安全的观察者模式

// 传感器数据事件
typedef struct
{
    float temperature;
    float pressure;
    float humidity;
    uint32_t timestamp;
} SensorDataEvent_t;

// 按键事件
typedef struct
{
    uint8_t key_id;
    bool is_pressed;
    uint32_t press_duration;
} ButtonEvent_t;

// 报警事件
typedef struct
{
    uint8_t alarm_type;
    uint8_t severity;
    char message[64];
} AlarmEvent_t;

// 类型安全的事件处理器
typedef void (*SensorDataHandler_t)(const SensorDataEvent_t *event, void *user_data);
typedef void (*ButtonEventHandler_t)(const ButtonEvent_t *event, void *user_data);
typedef void (*AlarmEventHandler_t)(const AlarmEvent_t *event, void *user_data);

// 类型安全的主题
typedef struct
{
    Subject_t base;
} SensorDataSubject_t;

typedef struct
{
    Subject_t base;
} ButtonEventSubject_t;

typedef struct
{
    Subject_t base;
} AlarmEventSubject_t;

// 类型安全的接口
bool SensorDataSubject_AddObserver(SensorDataSubject_t *subject, SensorDataHandler_t handler, void *user_data);
void SensorDataSubject_NotifyObservers(SensorDataSubject_t *subject, const SensorDataEvent_t *event);

bool ButtonEventSubject_AddObserver(ButtonEventSubject_t *subject, ButtonEventHandler_t handler, void *user_data);
void ButtonEventSubject_NotifyObservers(ButtonEventSubject_t *subject, const ButtonEvent_t *event);

bool AlarmEventSubject_AddObserver(AlarmEventSubject_t *subject, AlarmEventHandler_t handler, void *user_data);
void AlarmEventSubject_NotifyObservers(AlarmEventSubject_t *subject, const AlarmEvent_t *event);

🎨 实际应用场景

1. LFS流量计传感器数据通知

传感器数据发布订阅
// sensor_publisher.c - 传感器数据发布者

static SensorDataSubject_t sensor_data_subject;

// 初始化传感器发布者
void SensorPublisher_Init(void)
{
    Subject_Init(&sensor_data_subject.base, "SensorData");
}

// 传感器数据读取和发布
void SensorPublisher_Update(void)
{
    static uint32_t last_read_time = 0;
    uint32_t current_time = GetSystemTick();
    
    // 每100ms读取一次传感器数据
    if (current_time - last_read_time >= 100)
    {
        SensorDataEvent_t event;
        
        // 读取传感器数据
        event.temperature = ReadTemperatureSensor();
        event.pressure = ReadPressureSensor();
        event.humidity = ReadHumiditySensor();
        event.timestamp = current_time;
        
        // 通知所有观察者
        SensorDataSubject_NotifyObservers(&sensor_data_subject, &event);
        
        last_read_time = current_time;
    }
}

// 添加传感器数据观察者
bool SensorPublisher_AddObserver(SensorDataHandler_t handler, void *user_data)
{
    return SensorDataSubject_AddObserver(&sensor_data_subject, handler, user_data);
}
多个模块订阅传感器数据
// display_module.c - 显示模块(观察者)
void display_sensor_data_handler(const SensorDataEvent_t *event, void *user_data)
{
    // 更新显示内容
    LCD_ShowFloat(0, 0, "Temp: %.1f°C", event->temperature);
    LCD_ShowFloat(0, 20, "Press: %.1fkPa", event->pressure);
    LCD_ShowFloat(0, 40, "Humid: %.1f%%", event->humidity);
    
    printf("显示模块:更新传感器数据显示\n");
}

void DisplayModule_Init(void)
{
    // 订阅传感器数据
    SensorPublisher_AddObserver(display_sensor_data_handler, NULL);
}

// communication_module.c - 通信模块(观察者)
void comm_sensor_data_handler(const SensorDataEvent_t *event, void *user_data)
{
    // 检查是否有数据请求
    if (CommModule_HasDataRequest())
    {
        // 发送传感器数据
        char data_string[128];
        snprintf(data_string, sizeof(data_string),
                "TEMP:%.1f,PRESS:%.1f,HUMID:%.1f,TIME:%lu",
                event->temperature, event->pressure, 
                event->humidity, event->timestamp);
        
        CommModule_SendString(data_string);
        printf("通信模块:发送传感器数据\n");
    }
}

void CommModule_Init(void)
{
    // 订阅传感器数据
    SensorPublisher_AddObserver(comm_sensor_data_handler, NULL);
}

// alarm_module.c - 报警模块(观察者)
void alarm_sensor_data_handler(const SensorDataEvent_t *event, void *user_data)
{
    // 检查报警条件
    if (event->temperature > TEMP_ALARM_THRESHOLD)
    {
        AlarmEvent_t alarm_event = {
            .alarm_type = ALARM_TYPE_HIGH_TEMPERATURE,
            .severity = ALARM_SEVERITY_HIGH,
        };
        snprintf(alarm_event.message, sizeof(alarm_event.message),
                "温度过高: %.1f°C", event->temperature);
        
        // 触发报警事件
        AlarmEventSubject_NotifyObservers(&alarm_subject, &alarm_event);
        printf("报警模块:温度报警触发\n");
    }
}

void AlarmModule_Init(void)
{
    // 订阅传感器数据
    SensorPublisher_AddObserver(alarm_sensor_data_handler, NULL);
}

2. 按键事件处理系统

按键事件发布者
// button_publisher.c - 按键事件发布者

static ButtonEventSubject_t button_event_subject;

void ButtonPublisher_Init(void)
{
    Subject_Init(&button_event_subject.base, "ButtonEvent");
}

// 按键扫描和事件发布
void ButtonPublisher_Scan(void)
{
    static uint8_t last_key_state[MAX_KEYS] = {0};
    static uint32_t key_press_time[MAX_KEYS] = {0};
    
    for (uint8_t i = 0; i < MAX_KEYS; i++)
    {
        uint8_t current_state = ReadKeyState(i);
        uint32_t current_time = GetSystemTick();
        
        // 检测按键状态变化
        if (current_state != last_key_state[i])
        {
            ButtonEvent_t event = {
                .key_id = i,
                .is_pressed = current_state,
                .press_duration = current_state ? 0 : (current_time - key_press_time[i])
            };
            
            if (current_state)
            {
                key_press_time[i] = current_time;
            }
            
            // 发布按键事件
            ButtonEventSubject_NotifyObservers(&button_event_subject, &event);
            
            last_key_state[i] = current_state;
        }
    }
}

bool ButtonPublisher_AddObserver(ButtonEventHandler_t handler, void *user_data)
{
    return ButtonEventSubject_AddObserver(&button_event_subject, handler, user_data);
}
菜单系统订阅按键事件
// menu_module.c - 菜单模块(按键事件观察者)

void menu_button_handler(const ButtonEvent_t *event, void *user_data)
{
    if (!event->is_pressed) // 按键释放时处理
    {
        switch (event->key_id)
        {
            case KEY_UP:
                MenuModule_MoveCursorUp();
                break;
                
            case KEY_DOWN:
                MenuModule_MoveCursorDown();
                break;
                
            case KEY_ENTER:
                if (event->press_duration > LONG_PRESS_TIME)
                {
                    MenuModule_EnterSubMenu();
                }
                else
                {
                    MenuModule_SelectItem();
                }
                break;
                
            case KEY_BACK:
                MenuModule_GoBack();
                break;
        }
        
        // 更新菜单显示
        MenuModule_UpdateDisplay();
        printf("菜单模块:处理按键 %d\n", event->key_id);
    }
}

void MenuModule_Init(void)
{
    // 订阅按键事件
    ButtonPublisher_AddObserver(menu_button_handler, NULL);
}

🔧 高级观察者模式技巧

1. 优先级观察者

按优先级通知观察者
// priority_observer.h - 优先级观察者

typedef enum
{
    OBSERVER_PRIORITY_LOW = 0,
    OBSERVER_PRIORITY_NORMAL,
    OBSERVER_PRIORITY_HIGH,
    OBSERVER_PRIORITY_CRITICAL
} ObserverPriority_t;

typedef struct PriorityObserver
{
    EventHandler_t handler;
    void *user_data;
    ObserverPriority_t priority;
    struct PriorityObserver *next;
} PriorityObserver_t;

typedef struct
{
    PriorityObserver_t *observers[4]; // 按优先级分组
    uint32_t observer_counts[4];
} PrioritySubject_t;

// 按优先级添加观察者
bool PrioritySubject_AddObserver(PrioritySubject_t *subject, 
                                EventHandler_t handler, 
                                void *user_data,
                                ObserverPriority_t priority);

// 按优先级顺序通知观察者
void PrioritySubject_NotifyObservers(PrioritySubject_t *subject, const void *event_data)
{
    // 从高优先级到低优先级通知
    for (int priority = OBSERVER_PRIORITY_CRITICAL; priority >= OBSERVER_PRIORITY_LOW; priority--)
    {
        PriorityObserver_t *current = subject->observers[priority];
        while (current != NULL)
        {
            if (current->handler != NULL)
            {
                current->handler(event_data, current->user_data);
            }
            current = current->next;
        }
    }
}

2. 异步观察者

非阻塞事件通知
// async_observer.h - 异步观察者

#include "task_queue.h"

typedef struct
{
    EventHandler_t handler;
    void *event_data;
    size_t data_size;
    void *user_data;
} AsyncEventTask_t;

typedef struct
{
    Subject_t sync_subject;      // 同步观察者
    TaskQueue_t *async_queue;    // 异步任务队列
} AsyncSubject_t;

// 异步主题初始化
bool AsyncSubject_Init(AsyncSubject_t *subject, const char *name, size_t queue_size)
{
    if (!Subject_Init(&subject->sync_subject, name))
    {
        return false;
    }
    
    subject->async_queue = TaskQueue_Create(queue_size);
    return subject->async_queue != NULL;
}

// 添加同步观察者
bool AsyncSubject_AddSyncObserver(AsyncSubject_t *subject, EventHandler_t handler, void *user_data)
{
    return Subject_AddObserver(&subject->sync_subject, handler, user_data);
}

// 添加异步观察者
bool AsyncSubject_AddAsyncObserver(AsyncSubject_t *subject, EventHandler_t handler, void *user_data)
{
    // 异步观察者通过任务队列处理
    return true; // 实现省略
}

// 通知观察者(同步+异步)
void AsyncSubject_NotifyObservers(AsyncSubject_t *subject, const void *event_data, size_t data_size)
{
    // 立即通知同步观察者
    Subject_NotifyObservers(&subject->sync_subject, event_data);
    
    // 将异步观察者任务加入队列
    // 实现省略...
}

// 处理异步事件(在后台任务中调用)
void AsyncSubject_ProcessAsyncEvents(AsyncSubject_t *subject)
{
    AsyncEventTask_t task;
    while (TaskQueue_Dequeue(subject->async_queue, &task))
    {
        if (task.handler != NULL)
        {
            task.handler(task.event_data, task.user_data);
        }
        
        // 释放事件数据内存
        if (task.event_data != NULL)
        {
            free(task.event_data);
        }
    }
}

📚 参考资料

设计模式

  1. Observer Pattern - 观察者模式详解
  2. Gang of Four Design Patterns - 经典设计模式
  3. Publisher-Subscriber Pattern - 发布订阅模式
  4. Event-Driven Architecture - 事件驱动架构

嵌入式应用

  1. Embedded Observer Pattern - 嵌入式观察者模式
  2. Event-Driven Embedded Systems - 事件驱动嵌入式系统
  3. Interrupt-Driven Programming - 中断驱动编程
  4. Real-Time Event Processing - 实时事件处理

🏷️ 总结

观察者模式就像智能通知系统

  • 发布订阅让模块间松散耦合
  • 事件驱动提高系统响应性
  • 自动通知避免无效轮询
  • 易于扩展支持动态添加观察者

核心原则

  1. 松散耦合 > 紧密依赖
  2. 事件驱动 > 轮询检查
  3. 自动通知 > 主动查询
  4. 类型安全 > 通用接口

记住这个公式

优秀的观察者模式 = 松散耦合 + 事件驱动 + 自动通知 + 类型安全

通过本文的学习,我们了解了观察者模式的原理和最佳实践,掌握了构建高效事件驱动系统的方法。


观察者模式是事件驱动编程的核心,让你的代码像智能通知系统一样高效响应! 👁️

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐