观察者模式
2026/8/24大约 2 分钟
观察者模式在裸机与 RTOS 中的实现
一、先记住本质
观察者模式就是:
一个事件发生,通知多个关心它的对象。
例如:
温度变化
↓
┌─┼─┐
↓ ↓ ↓
OLED 蜂鸣器 日志二、裸机:函数指针就很好用
裸机没有任务调度,最简单的方式就是函数指针 + 回调。
typedef void (*Observer)(int event);
Observer observers[5];
int count;注册:
void register_observer(Observer obs)
{
observers[count++] = obs;
}通知:
void notify(int event)
{
for (int i = 0; i < count; i++)
observers[i](event);
}事件发生:
notify(EVENT_TEMP_UPDATE);执行过程:
事件发生
↓
遍历函数指针数组
↓
callback1()
callback2()
callback3()这里的特点是:
直接调用,同步执行。
三、RTOS:函数指针依然可以用
RTOS 并不会禁止函数指针。
例如一个任务检测到事件:
notify(event);然后:
callback1(event);
callback2(event);
callback3(event);一样能够实现观察者模式。
所以:
函数指针观察者模式不是“裸机专属”。
四、但是 RTOS 有更合适的通信机制
如果你的需求变成:
“把消息交给其他任务,让其他任务自己处理。”
这时候就应该考虑:
消息队列
任务通知
信号量例如:
SensorTask
↓
温度数据
↓
┌──┼──┐
↓ ↓ ↓
Q1 Q2 Q3
↓ ↓ ↓
OLED 蜂鸣器 日志任务每个任务从自己的队列获取消息。
五、函数指针和消息队列的核心区别
函数指针
callback(event);本质:
发生事件
↓
立即调用
↓
函数执行属于同步调用。
消息队列
xQueueSend(queue, &msg, ...);本质:
发生事件
↓
消息进入队列
↓
任务被唤醒
↓
任务自己处理属于任务间异步通信。
六、什么时候用哪个?
裸机
↓
简单事件通知
↓
函数指针 / 回调
RTOS
↓
简单事件分发
↓
函数指针也可以
RTOS
↓
任务之间传数据
↓
消息队列
RTOS
↓
只需要唤醒任务
↓
任务通知七、实际项目可以组合使用
真正的项目里经常不是二选一:
硬件中断
↓
驱动回调
↓
函数指针
↓
发布事件
↓
消息队列 / 任务通知
↓
RTOS任务例如 UART 接收完成:
UART中断
↓
HAL回调
↓
通知通信任务
↓
任务从队列取数据
↓
协议解析这样:
- 函数指针负责解耦驱动和上层;
- RTOS通信机制负责任务之间的数据传递和同步。
八、最终记忆
函数指针解决“调用谁”。
消息队列解决“消息怎么交给任务”。
任务通知解决“怎么通知任务”。
所以:
裸机:
函数指针 + 回调
↓
已经很好用
RTOS:
函数指针
+
消息队列 / 任务通知
↓
根据需求组合使用不要因为用了 RTOS 就把函数指针扔掉。它们解决的是不同层面的问题。

