23種設計模式 之 Observer模式(觀察者模式)[C語言實現]
一、概念定義
Observer模式又稱為釋出-訂閱模式。
Observer模式:定義了一種一對多的依賴關係,讓多個觀察者(Observer)同時監聽某一主題物件(Subject)。當這個主題物件(Subject)的狀態發生變化時,會通知觀察者物件(Observer),讓他們能夠自動更新自己。
二、模式結構圖
圖1 Observer模式結構圖
三、場景設計
當同一組資料進行分析統計時,我們希望能夠提供多種形式的表示,如:以表格統計顯示、以柱狀圖統計顯示、以百分比統計顯示等等。這些表示都依賴於同一組資料,當這些資料發生改變時,所有的統計顯示同時也要發生變化。
四、C語言實現
分析:表格顯示、柱狀圖顯示和百分比顯示相當於觀察者(Observer),而統計資料相當於被觀察的主題物件(Subject)。
// 型別定義(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