1、为什么会有耦合问题出现?
开始先讲个例子:关于按键驱动。
我们在按键驱动 里面,往往同样会写,在按键被按下后,执行相应动作 ,恰恰这个动作又与按键本身无关,这就造成了耦合,即按键驱动里面,有其他的文件的函数,驱动它本应该只关心只与按键有关的事情。(疑问:那能不能在外面读取、获得按键的值后,再执行对应的操作,不一定都要放驱动里面?可能放在驱动里面的好处是,测试代码也可以在驱动文件内完成)


2、回调函数解耦操作


以上驱动代码里面只有与按键相关的代码,即没有包含别的头文件

应用层,注册回调函数:有个精华地方,注册函数可以回参数。
button_register_callback(BUTTON_EVENT_SINGLE_CLICK, on_button_single_click, NULL);
button_register_callback(BUTTON_EVENT_LONG_PRESS, on_button_long_press, &led_for_long_press);
3、观察者登场


先不看subject的那些函数,因为看不懂。主要看subject_t结构体与observer_t变量:
subject_t的:num_observers有几个需要接收消息的对象;


subject_set_value会通知所有订阅了g_temp_sensor的设备
以上代码补全后,如下
cpp
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
// -------------------------- observer.h 内容 --------------------------
typedef struct {
// update 方法,当被观察者状态改变时调用
// observer 指针用于区分不同的观察者实例
void (*update)(void *observer, int value);
} observer_t;
// -------------------------- subject.h 内容 --------------------------
#define MAX_OBSERVERS 10
typedef struct {
observer_t* observers[MAX_OBSERVERS];
int num_observers;
int value; // 被观察的状态(温度)
} subject_t;
void subject_init(subject_t *sub);
bool subject_attach(subject_t *sub, observer_t *obs);
bool subject_detach(subject_t *sub, observer_t *obs);
void subject_notify(subject_t *sub);
void subject_set_value(subject_t *sub, int new_value);
// -------------------------- subject.c 内容 --------------------------
// 初始化被观察者
void subject_init(subject_t *sub) {
if (sub == NULL) return; // 空指针保护
sub->num_observers = 0; // 观察者数量初始化为0
sub->value = 0; // 初始温度设为0
// 清空观察者列表(避免野指针)
memset(sub->observers, 0, sizeof(sub->observers));
}
// 添加观察者(返回是否成功)
bool subject_attach(subject_t *sub, observer_t *obs) {
// 边界检查:被观察者/观察者为空、列表已满
if (sub == NULL || obs == NULL || sub->num_observers >= MAX_OBSERVERS) {
return false;
}
// 避免重复添加同一个观察者
for (int i = 0; i < sub->num_observers; ++i) {
if (sub->observers[i] == obs) {
return false;
}
}
// 添加到列表末尾,数量+1
sub->observers[sub->num_observers++] = obs;
return true;
}
// 移除观察者(返回是否成功)
bool subject_detach(subject_t *sub, observer_t *obs) {
if (sub == NULL || obs == NULL || sub->num_observers == 0) {
return false;
}
// 查找观察者位置
int target_idx = -1;
for (int i = 0; i < sub->num_observers; ++i) {
if (sub->observers[i] == obs) {
target_idx = i;
break;
}
}
// 未找到则返回失败
if (target_idx == -1) {
return false;
}
// 找到则移动数组(覆盖被移除的位置)
for (int i = target_idx; i < sub->num_observers - 1; ++i) {
sub->observers[i] = sub->observers[i + 1];
}
sub->num_observers--; // 数量-1
sub->observers[sub->num_observers] = NULL; // 清空最后一个位置(可选,安全)
return true;
}
void subject_notify(subject_t *sub) {
if (sub == NULL) return; // 空指针保护
for (int i = 0; i < sub->num_observers; ++i) {
// 调用每个观察者的 update 方法
if (sub->observers[i] != NULL && sub->observers[i]->update != NULL) {
sub->observers[i]->update(sub->observers[i], sub->value);
}
}
}
void subject_set_value(subject_t *sub, int new_value) {
if (sub == NULL) return; // 空指针保护
if (sub->value != new_value) {
sub->value = new_value;
// 状态改变,通知所有观察者
subject_notify(sub);
}
}
// -------------------------- display_module.c 内容 --------------------------
void display_update(void *observer, int temperature) {
printf("Display: Temperature is now %d C\n", temperature);
}
observer_t g_display_observer = { .update = display_update };
// -------------------------- alarm_module.c 内容 --------------------------
void alarm_update(void *observer, int temperature) {
if (temperature > 50) {
printf("Alarm: DANGER! Temperature is %d C!\n", temperature);
}
}
observer_t g_alarm_observer = { .update = alarm_update };
// -------------------------- main.c 内容 --------------------------
subject_t g_temp_sensor;
int main() {
// 初始化温度传感器
subject_init(&g_temp_sensor);
// 订阅观察者
subject_attach(&g_temp_sensor, &g_display_observer);
subject_attach(&g_temp_sensor, &g_alarm_observer);
// 模拟温度变化
subject_set_value(&g_temp_sensor, 25); // 仅显示器输出:25℃
subject_set_value(&g_temp_sensor, 60); // 显示器+报警器输出:60℃ + 危险提示
// 取消报警器订阅
subject_detach(&g_temp_sensor, &g_alarm_observer);
subject_set_value(&g_temp_sensor, 70); // 仅显示器输出:70℃
return 0;
}