概述
观察者模式(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博客

 

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐