通過C語言實現#軟件設計模式#觀察者模式

一. 定義

觀察者模式定義:當對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並自動更新,也可以稱這種模式發佈-訂閱模式

二.應用場景

應用場景:Excel 中的數據與折線圖、餅狀圖、柱狀圖之間的關係;MVC 模式中的模型與視圖的關係;事件模型中的事件源與事件處理者等等

三.優缺點

主要優點有,降低了目標與觀察者之間的耦合關係,兩者之間是抽象耦合關係,目標與觀察者之間建立了一套觸發機制
當然也有缺點:當觀察者對象很多時,通知的發佈會花費很多時間,影響程序的效率
所謂技術利弊兩面,取決於具體應用需求

四.模式結構

觀察者模式的結構如下。

  1. 抽象主題(Subject)角色:也叫抽象目標類,它提供了一個用於保存觀察者對象的集合和增加、刪除觀察者對象的方法,以及通知所有觀察者的抽象方法。

  2. 抽象觀察者(Observer)角色:它是一個抽象類或接口,它包含了一個更新自己的抽象方法,當接到具體主題的更改通知時被調用

結構圖如下:
在這裏插入圖片描述

五.C語言實現

具體實現源碼如下:源碼github獲取

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

/**
 * @brief 觀察者抽象類
 * @note adapter 適配接口,適配主題 update_proc 更新處理接口
 */
typedef struct Observer_t
{
    char name[32];
    bool (*adapter)(char *themeName);
    bool (*update_proc)(struct Observer_t *observerObj, char *themeName);
}Observer_t;

/**
 * @brief 主題抽象類
 * @note register_list 觀察者列表 add 觀察者註冊接口 del 註銷觀察者接口
 * @note notify 通知觀察者接口,這裏可以實現爲同步或者異步通知
 */
typedef struct Subject_t
{
    char name[32];
    struct Observer_t *register_list[10];
    bool (*add)(struct Subject_t *subjectobj, struct Observer_t * observerobj);
    bool (*del)(struct Subject_t *subjectobj, struct Observer_t * observerobj);
    bool (*notify)(struct Subject_t * subjectObj, char *event);
}Subject_t;

/**
 * @brief adapter
 * @param themeName 主題名
 * @return true適配成功 otherwise false 適配失敗
 * @note 對主題過濾,對適配的主題進行通知
 */
bool adapter(char *themeName)
{
    if (0 == strcasecmp(themeName, "csdn-blog"))
        return true;
    else
        return true;
}

/**
 * @brief update_proc
 * @param observerObj 觀察者 themeName 主題
 * @return true
 * @note 更新主題,或者處理對應事件
 */
bool update_proc(Observer_t *observerObj, char *themeName)
{
    printf("[%s]收到[%s]主題跟新通知.....\n",        observerObj->name, themeName);

    return true;
}

/**
 * @brief add
 * @param subjectObj 主題對象
 * @param observerObj 觀察者對象
 * @return true 註冊進觀察者列表成功,else false 註冊失敗
 * @note 觀察者對象註冊
 */
bool add(Subject_t *subjectObj, Observer_t *observerObj)
{
    
    for(int i = 0; i < (sizeof(subjectObj->register_list)/sizeof(subjectObj->register_list[0])); i++)
    {
        if (subjectObj->register_list[i] == NULL)
        {
            subjectObj->register_list[i] = observerObj;
            return true;
        }
    }
    
    return false;
}

/**
 * @brief del
 * @param subjectObj 主題對象
 * @param observerObj 觀察者對象
 * @return true 註銷進觀察者列表成功,else false 註冊失敗
 * @note 觀察者對象註銷
 */
bool del(Subject_t * subjectObj, Observer_t *observerObj)
{
    for (int i = 0; i< (sizeof(subjectObj->register_list)/sizeof(subjectObj->register_list[0])); i++)
    {
        if (subjectObj->register_list[i] == observerObj)
        {
            subjectObj->register_list[i] = NULL;
            free(observerObj);
            return true;
        }
    }
    
    return false;
}

/**
 * @brief notify
 * @param subjectObj 主題對象
 * @param event 通知事件
 * @return true
 * @note 通知到所有觀察者
 */
bool notify(Subject_t * subjectObj, char *event)
{
    for(int i = 0; i< (sizeof(subjectObj->register_list)/sizeof(subjectObj->register_list[0])); i++)
    {
        if (NULL == subjectObj->register_list[i])
            continue;
        
        if (subjectObj->register_list[i]->adapter(event))
            subjectObj->register_list[i]->update_proc(subjectObj->register_list[i], \
                                                      subjectObj->name);
    }
    
    return true;
}

/**
 * @brief Observer_new
 * @param name 對象名字
 * @return observerobj
 * @note 創建一個觀察者對象
 */
Observer_t* Observer_new(char *name)
{
    Observer_t * p;
    
    p = malloc(sizeof(*p));
    if (!p)
        return NULL;
    
    memcpy(p->name, name, strlen(name));
    p->adapter = adapter;
    p->update_proc = update_proc;
    return p;
}

/**
 * @brief Subject_new
 * @param name 對象名字
 * @return subjectobj
 * @note 創建一個主題對象
 */
Subject_t* Subject_new(char * name)
{
    Subject_t * p;

    p = malloc(sizeof(*p));
    if (!p)
        return NULL;
    memset(p, 0x00, sizeof(*p));
    memcpy(p->name, name, strlen(name));
    p->add = add;
    p->del = del;
    p->notify = notify;
}

int main(void)
{
    Subject_t *subject;
    Observer_t *observerA;
    Observer_t *observerB;
    Observer_t *observerC;
    
    printf("start to create subjecter and observer.....\n");
    // 創建一個主題
    subject = Subject_new("creater");
    //創建多個消費者
    observerA = Observer_new("readerA");
    observerB = Observer_new("readerB");
    observerC = Observer_new("readerC");

    // 添加消費者到觀察者列表
    subject->add(subject, observerA);
    subject->add(subject, observerB);
    subject->add(subject, observerC);
    
    // 通知給所有讀者
    subject->notify(subject, "csdn-blog");
}

六.總結

當一個對象的改變需要同時改變其它對象,並且它不知道具體有多少對象有待改變的時候,應該考慮使用觀察者模式,同時觀察者模式所做的工作也是在解除耦合,各個對象互爲獨立工作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章