首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言實現觀察者模式:委託/事件機制完整框架

     編輯:關於C語言

設計目標

在純 C 環境(RT-Thread + Finsh Shell)中實現類 C# 的 event/delegate 機制,支援:多播委託、動態增減訂閱、型別安全的回調調用。以「老板通知同事關閉股票/ NBA」為例示。

核心資料結構

1. 動態陣列 List

typedef struct _List {
    void** items; int count;
    void (*Add)(struct _List*, void*);
    void (*Remove)(struct _List*, void*);
    void (*Delete)(void*);
} List;
  • Add:重新分配 count+1 空間,去重後追加;
  • Remove:分配 count-1 空間,過濾目標指標;
  • Delete:釋放 items 再釋放自身。

2. 委託容器 Entrust

typedef void (*Event)(void*);      // 回調簽名:單一 void* 參數
typedef struct _Entrust {
    List* funcs;
    void (*Add)(struct _Entrust*, void* callback);
    void (*Remove)(struct _Entrust*, void* callback);
    void (*Update)(struct _Entrust*);   // 遍歷調用所有回調
    void (*Delete)(void*);
} Entrust;

Update 逐個取出函數指標並調用:(*(Event*)funcPtr)(funcPtr),利用「函數指標即物件」特性,將同一指標同時作為 this 與回調入口。

3. 具體通知者 Boss

typedef struct _Boss {
    Entrust* evt;
    char* action;
    char* (*GetState)(void*);
    void (*SetState)(void*, char*);
    void (*Notify)(void*);            // 呼叫 evt->Update()
    void (*Delete)(void*);
} Boss;

4. 具體觀察者 StockObserver / NBAObserver

typedef struct _StockObserver {
    char* name; Boss* sub;
    void (*CloseStock)(void*);        // 回調函數
    void (*Delete)(void*);
} StockObserver;

// 關鍵技巧:從回調指標反推物件指標
#define ClassEntry(ptr, type, member) \
    ((type*)((char*)(ptr) - (unsigned long)&(((type*)0)->member)))

static void CloseStock(void* p) {
    auto obs = ClassEntry(p, StockObserver, CloseStock);
    rt_kprintf(" %s,%s關閉股票行情,繼續工作\n",
               obs->sub->GetState(obs->sub), obs->name);
}

客戶端測試代碼

void EntrustObs(void) {
    Boss* huhasan = BossCreate(sizeof(Boss));
    StockObserver* ws1 = StockObserverCreate("魏關姹", huhasan, sizeof(StockObserver));
    NBAObserver* ws2 = NBAObserverCreate("易管查", huhasan, sizeof(NBAObserver));

    huhasan->evt->Add(huhasan->evt, &(ws1->CloseStock));
    huhasan->evt->Add(huhasan->evt, &(ws2->CloseNBA));

    huhasan->SetState(huhasan, "我胡漢三回來啦");
    huhasan->Notify(huhasan);        // 觸發兩個回調

    huhasan->Delete(huhasan);
    ws1->Delete(ws1); ws2->Delete(ws2);
}
FINSH_FUNCTION_EXPORT(EntrustObs, Entrust Observer Modle);

關鍵技術點總結

  • ClassEntry 巨集:標準 C 技巧,從成員指標計算物件基址,實現「這裡是回調,那裡是 this」;
  • 函數指標雙重身份:既是回調入口,又作為 List 節點值與物件識別 token;
  • 動態記憶體管理:所有物件 rt_malloc/rt_free,符合嵌入式環境;
  • Shell 整合:FINSH_FUNCTION_EXPORT 讓測試函數直接在命令列呼叫。

擴展方向

可進一步封裝為泛型 Event<T>(以巨集生成特化版本)、加入線程安全鎖、支援優先級調用、異步佇列等。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved