1. 程式人生 > >23種設計模式 之 Observer模式(觀察者模式)[C語言實現]

23種設計模式 之 Observer模式(觀察者模式)[C語言實現]

一、概念定義

Observer模式又稱為釋出-訂閱模式。

Observer模式:定義了一種一對多的依賴關係,讓多個觀察者(Observer)同時監聽某一主題物件(Subject)。當這個主題物件(Subject)的狀態發生變化時,會通知觀察者物件(Observer),讓他們能夠自動更新自己。

二、模式結構圖


圖1 Observer模式結構圖

三、場景設計

當同一組資料進行分析統計時,我們希望能夠提供多種形式的表示,如:以表格統計顯示、以柱狀圖統計顯示、以百分比統計顯示等等。這些表示都依賴於同一組資料,當這些資料發生改變時,所有的統計顯示同時也要發生變化。

四、C語言實現

分析:表格顯示、柱狀圖顯示和百分比顯示相當於觀察者(Observer),而統計資料相當於被觀察的主題物件(Subject)。

(注:使用C語言實現設計模式時,可以根據具體場景,將類理解為結構體或一組函式(元件)等)

// 型別定義(Observer和Subject)

1. 觀察者

// 觀察者回調
typedef struct
{
    ...
    void (*update)(int);
    ...
}observer_t;

2. 被觀察者

// 觀察者連結串列
typedef struct _observer_link_t
{
    observer_t *observer;
    struct _observer_link_t *next;
}observer_link_t;
// 被觀察者
typedef struct _subject_t
{
    int data;                 // 被觀察資料
    observer_link_t *observer; // 觀察者連結串列(佇列)
}subject_t;

// 更新統計(觀察者更新)
1. 更新 表格統計顯示

void updateform(int data){...}
...

2. 更新 柱狀圖統計顯示

void updatecylinder(int data){...}
...

3. 更新 百分比統計顯示

void updatepercent(int data){...}
...

4. 初始化觀察者

void initobserver(observer_t *observer, void (*update)(int))
{
    ...
    observer.update = update;
    ...
}
...

// 統計資料(Subject介面)

// 加入觀察者佇列
int attachobserver(subject_t *subject, observer_t *observer)
{
    // 將observer加入subject中的observer連結串列
}
// 從觀察者佇列刪除
int detachobserver(subject_t *subject, observer_t *observer)
{
    // 將observer踢出subject中的observer連結串列
}
// 修改被觀察資料
int setdata(subject_t *subject, int *value)
{
    subject->data = value;
}
// 通知觀察者
void notifyobserver(subject_t *subject)
{
    observer_link_t *node = subject->observer;

    while(NULL != node)
    {
        node->update(subject->data);
    }
    ...
}
// 初始化主題物件
void initsubject(subject_t *subject)
{
    memset(subject, 0, sizeof(subject_t));
    subject->observer = NULL;
}

// Observer模式使用

int main(int argc, const char *agrc[])
{
    observer_t form;       // 表格物件
    observer_t cylinder; // 柱狀圖物件
    observer_t percent; // 百分比物件
    subject_t subject;    // 統計資料

    // 初始化觀察者
    initobserver(&form, updateform);
    initobserver(&cylinder, updatecylinder);
    initobserver(&percent, updatepercent);

    // 初始化被觀察者
    initsubject(&subject);

    // 觀察者關注subject
    attachobserver(&subject, &form);
    attachobserver(&subject, &cylinder);
    attachobserver(&subject, &percent);

    // 修改狀態,並通知觀察者
    setdata(&subject, 1);
    notifyobserver(&subject);
   
    setdata(&subject, 2);
    notifyobserver(&subject);
 
    ...

    return 0;
}


作者:鄒祁峰

2012.11.15

一、概念定義

Observer模式又稱為釋出-訂閱模式。

Observer模式:定義了一種一對多的依賴關係,讓多個觀察者(Observer)同時監聽某一主題物件(Subject)。當這個主題物件(Subject)的狀態發生變化時,會通知觀察者物件(Observer),讓他們能夠自動更新自己。

二、模式結構圖


圖1 Observer模式結構圖

三、場景設計

當同一組資料進行分析統計時,我們希望能夠提供多種形式的表示,如:以表格統計顯示、以柱狀圖統計顯示、以百分比統計顯示等等。這些表示都依賴於同一組資料,當這些資料發生改變時,所有的統計顯示同時也要發生變化。

四、C語言實現

分析:表格顯示、柱狀圖顯示和百分比顯示相當於觀察者(Observer),而統計資料相當於被觀察的主題物件(Subject)。(注:使用C語言實現設計模式時,可以根據具體場景,將類理解為結構體或一組函式(元件)等)

// 型別定義(Observer和Subject)

1. 觀察者

// 觀察者回調
typedef struct
{
    ...
    void (*update)(int);
    ...
}observer_t;

2. 被觀察者

// 觀察者連結串列
typedef struct _observer_link_t
{
    observer_t *observer;
    struct _observer_link_t *next;
}observer_link_t;
// 被觀察者
typedef struct _subject_t
{
    int data;                 // 被觀察資料
    observer_link_t *observer; // 觀察者連結串列(佇列)
}subject_t;

// 更新統計(觀察者更新)
1. 更新 表格統計顯示

void updateform(int data){...}
...

2. 更新 柱狀圖統計顯示

void updatecylinder(int data){...}
...

3. 更新 百分比統計顯示

void updatepercent(int data){...}
...

4. 初始化觀察者

void initobserver(observer_t *observer, void (*update)(int))
{
    ...
    observer.update = update;
    ...
}
...

// 統計資料(Subject介面)

// 加入觀察者佇列
int attachobserver(subject_t *subject, observer_t *observer)
{
    // 將observer加入subject中的observer連結串列
}
// 從觀察者佇列刪除
int detachobserver(subject_t *subject, observer_t *observer)
{
    // 將observer踢出subject中的observer連結串列
}
// 修改被觀察資料
int setdata(subject_t *subject, int *value)
{
    subject->data = value;
}
// 通知觀察者
void notifyobserver(subject_t *subject)
{
    observer_link_t *node = subject->observer;

    while(NULL != node)
    {
        node->update(subject->data);
    }
    ...
}
// 初始化主題物件
void initsubject(subject_t *subject)
{
    memset(subject, 0, sizeof(subject_t));
    subject->observer = NULL;
}

// Observer模式使用

int main(int argc, const char *agrc[])
{
    observer_t form;       // 表格物件
    observer_t cylinder; // 柱狀圖物件
    observer_t percent; // 百分比物件
    subject_t subject;    // 統計資料

    // 初始化觀察者
    initobserver(&form, updateform);
    initobserver(&cylinder, updatecylinder);
    initobserver(&percent, updatepercent);

    // 初始化被觀察者
    initsubject(&subject);

    // 觀察者關注subject
    attachobserver(&subject, &form);
    attachobserver(&subject, &cylinder);
    attachobserver(&subject, &percent);

    // 修改狀態,並通知觀察者
    setdata(&subject, 1);
    notifyobserver(&subject);
   
    setdata(&subject, 2);
    notifyobserver(&subject);
 
    ...

    return 0;
}


作者:鄒祁峰

2012.11.15