分布式软总线连接模块中观察者模式原理设计分析
概述
观察者模式(Observer Pattern)是分布式软总线连接模块的核心架构模式,它定义了一种一对多的依赖关系:当一个对象(被观察者/Subject)的状态发生改变时,所有依赖于它的对象(观察者/Observer)都会收到通知并自动更新。
在连接模块中,连接管理器(ConnManager)是被观察者,各业务模块(认证、通道、代理等)是观察者。这种设计使得连接状态的变化能够自动、透明地传播给所有关心的业务方,实现了松耦合的事件驱动架构。
一、观察者模式原理深度解析
1.1 模式定义与角色
观察者模式属于行为型设计模式,其经典结构包含四个角色:
角色 英文 职责
主题接口 Subject 定义注册、删除、通知观察者的方法
具体主题 ConcreteSubject 维护观察者列表,状态变化时通知
观察者接口 Observer 定义接收通知的更新方法
具体观察者 ConcreteObserver 实现具体的响应逻辑
1.2 经典UML类图

1.3 核心机制
// 伪代码展示观察者模式的核心逻辑
// 1. 注册观察者
void attach(Observer *observer) {
observerList.add(observer);
}
// 2. 删除观察者
void detach(Observer *observer) {
observerList.remove(observer);
}
// 3. 状态变化时通知所有观察者
void notify() {
for (Observer *observer : observerList) {
observer->update(this->state); // 推送方式
// 或: observer->pull(); // 拉取方式
}
}
1.4 两种通知方式
方式 特点 适用场景
Push推送 被动接收,Subject主动传递数据 数据确定且需要立即处理
Pull拉取 主动获取,Observer按需查询 数据量大或需要选择性获取
二、连接模块观察者模式的具体实现
2.1 核心数据结构
2.1.1 观察者回调接口(ConnectCallback)
定义在 softbus_conn_interface.h:
typedef struct {
void (*OnConnected)(uint32_t connectionId, const ConnectionInfo *info); // 连接建立
void (*OnReusedConnected)(uint32_t connectionId, const ConnectionInfo *info); // 连接复用
void (*OnDisconnected)(uint32_t connectionId, const ConnectionInfo *info); // 连接断开
void (*OnDataReceived)(uint32_t connectionId, ConnModule moduleId, int64_t seq,
char *data, int32_t len); // 数据到达
} ConnectCallback;
这是观察者接口的定义,每个业务模块必须实现这四个回调函数来响应连接事件。
2.1.2 观察者节点(ConnListenerNode)
定义在 softbus_conn_manager.c:
typedef struct TagConnListenerNode {
ListNode node; // 链表节点(内核风格链表)
ConnModule moduleId; // 业务模块标识符
ConnectCallback callback; // 回调函数集
} ConnListenerNode;
每个节点代表一个已注册的业务观察者:
moduleId — 唯一标识该观察者(如 MODULE_AUTH_CHANNEL、MODULE_PROXY_CHANNEL)
callback — 该观察者提供的四个事件处理函数
2.1.3 被观察者全局容器
static SoftBusList *g_listenerList = NULL; // 全局观察者链表
2.2 注册与注销机制
2.2.1 注册观察者(AddListener)
static int32_t AddListener(ConnModule moduleId, const ConnectCallback *callback)
{
// 1. 参数校验
if (g_listenerList == NULL) { return SOFTBUS_INVALID_PARAM; }
// 2. 加锁保护(线程安全)
if (SoftBusMutexLock(&g_listenerList->lock) != SOFTBUS_OK) { return SOFTBUS_LOCK_ERR; }
// 3. 去重检查(同一模块只能注册一次)
LIST_FOR_EACH_ENTRY(listNode, &g_listenerList->list, ConnListenerNode, node) {
if (listNode->moduleId == moduleId) {
(void)SoftBusMutexUnlock(&g_listenerList->lock);
return SOFTBUS_CONN_INTERNAL_ERR; // 已存在则返回错误
}
}
// 4. 创建新节点并加入链表
item = (ConnListenerNode *)SoftBusCalloc(sizeof(ConnListenerNode));
item->moduleId = moduleId;
item->callback = *callback;
ListAdd(&(g_listenerList->list), &(item->node));
g_listenerList->cnt++;
(void)SoftBusMutexUnlock(&g_listenerList->lock);
return SOFTBUS_OK;
}
关键设计点:
✅ 互斥锁保护 — 多线程环境下安全注册
✅ 去重机制 — 同一模块ID只允许注册一次
✅ 动态内存分配 — 支持运行时增删观察者
2.2.2 注销观察者(DelListener)
static void DelListener(ConnModule moduleId)
{
if (SoftBusMutexLock(&g_listenerList->lock) != SOFTBUS_OK) return;
LIST_FOR_EACH_ENTRY(removeNode, &g_listenerList->list, ConnListenerNode, node) {
if (removeNode->moduleId == moduleId) {
ListDelete(&(removeNode->node)); // 从链表移除
SoftBusFree(removeNode); // 释放内存
g_listenerList->cnt--;
break;
}
}
(void)SoftBusMutexUnlock(&g_listenerList->lock);
}
2.2.3 对外接口
int32_t ConnSetConnectCallback(ConnModule moduleId, const ConnectCallback *callback)
{
// 1. 校验模块ID合法性
ModuleCheck(moduleId);
// 2. 校验回调函数完整性
if ((callback->OnConnected == NULL) ||
(callback->OnDisconnected == NULL) ||
(callback->OnDataReceived == NULL)) {
return SOFTBUS_INVALID_PARAM;
}
return AddListener(moduleId, callback);
}
void ConnUnSetConnectCallback(ConnModule moduleId)
{
DelListener(moduleId);
}
2.3 事件通知机制(核心分发逻辑)
连接管理器实现了四种不同粒度的事件通知:
2.3.1 广播式通知(连接建立/断开)
场景:连接建立或断开时,所有业务模块都需要知道
void ConnManagerConnected(uint32_t connectionId, const ConnectionInfo *info)
{
// 1. 获取所有观察者的快照(避免长时间持锁)
int32_t num = GetAllListener(&node);
// 2. 遍历所有观察者,逐一通知
for (int32_t i = 0; i < num; i++) {
listener = node + i;
listener->callback.OnConnected(connectionId, info); // 调用每个观察者的回调
}
SoftBusFree(node);
}
void ConnManagerDisconnected(uint32_t connectionId, const ConnectionInfo *info)
{
// 同上,广播断连事件
for (int32_t i = 0; i < num; i++) {
listener->callback.OnDisconnected(connectionId, info);
}
}
特点:
📡 一对多广播 — 一个事件通知所有观察者
🔄 无差别通知 — 所有观察者都收到相同的信息
📦 快照拷贝 — 先复制链表再遍历,减少锁持有时间
2.3.2 选择性通知(数据接收)
场景:数据到达时,只有发送数据的源模块应该收到
void ConnManagerRecvData(uint32_t connectionId, ConnModule moduleId, int64_t seq,
char *data, int32_t len)
{
// 1. 根据moduleId精确查找目标观察者
ConnListenerNode listener = { 0 };
int32_t status = GetListenerByModuleId(moduleId, &listener);
// 2. 只通知目标模块
if (status == SOFTBUS_OK) {
int32_t pktLen = len - sizeof(ConnPktHead);
char *pkt = data + sizeof(ConnPktHead);
listener.callback.OnDataReceived(connectionId, moduleId, seq, pkt, pktLen);
}
}
特点:
🎯 精确路由 — 按 moduleId 定位唯一目标观察者
📊 数据解包 — 自动剥离协议头(ConnPktHead),只传递有效载荷
⚡ 高效查找 — O(n)线性搜索,但实际观察者数量少(通常<20个)
2.3.3 可选通知(连接复用)
场景:连接复用时,部分模块可能不关心此事件
void ConnManagerReusedConnected(uint32_t connectionId, const ConnectionInfo *info)
{
for (int32_t i = 0; i < num; i++) {
listener = node + i;
if (listener->callback.OnReusedConnected != NULL) { // 安全检查
listener->callback.OnReusedConnected(connectionId, info);
}
}
}
特点:
🔒 空指针保护 — 允许观察者不实现可选回调
🎛️ 渐进式接口 — 核心回调必填,扩展回调可选
2.4 观察者管理辅助函数
// 获取所有观察者快照(用于广播)
static int32_t GetAllListener(ConnListenerNode **node);
// 按模块ID获取单个观察者(用于精确投递)
static int32_t GetListenerByModuleId(ConnModule moduleId, ConnListenerNode *node);
Lobster AI
2.5 初始化时的桥接设置
int32_t ConnServerInit(void)
{
// ... 其他初始化 ...
// 将管理器的内部函数包装为统一的回调接口
g_connManagerCb.OnConnected = ConnManagerConnected; // 连接建立 → 广播
g_connManagerCb.OnReusedConnected = ConnManagerReusedConnected; // 复用 → 可选广播
g_connManagerCb.OnDisconnected = ConnManagerDisconnected; // 断连 → 广播
g_connManagerCb.OnDataReceived = ConnManagerRecvData; // 数据 → 精确投递
// 将此回调传递给各连接类型实现
g_connManager[CONNECT_TCP] = ConnInitTcp(&g_connManagerCb);
g_connManager[CONNECT_BR] = ConnInitBr(&g_connManagerCb);
g_connManager[CONNECT_BLE] = ConnInitBle(&g_connManagerCb);
}
架构意义:
各底层连接实现(BR/BLE/TCP)通过这个统一回调向上报告事件
连接管理器作为中介者,将事件分发给正确的业务观察者
2.6 完整的事件流转图

详见分布式软总线连接模块中观察者模式原理设计分析-CSDN博客
更多推荐
所有评论(0)