概述
观察者模式让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
之前的文章已经详细阐述了这种设计模式的核心和注意事项,并完成了基类设计,请参见《我用C语言玩对象,偷偷关注着你的观察者模式(基类设计)》,本文将结合实际案例论证这种设计模式,加深读者对观察者模式的理解和应用。
示例
★背景说明:人民日报+订阅者=观察者模式。只要是订阅了人民日报的人,有了新报纸就会送到订阅者那里去,当你不想订的时候取消就不订阅就不会再收到报纸了。
★被观察者对象(人民日报):
属性:无
行为:获取报纸。
继承:继承被观察者基类
★观察者对象(订阅者):
属性:名字
行为:对应行为。
★包含头文件newspaper.h和源文件newspaper.c(均已验证通过)。
newspaper.h
/** * @Filename : newspaper.h * @Revision : $Revision: 1.0 $ * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅) * @Description : 观察者模式应用(C语言模拟C++) * @Explain : 报纸(被观察者) newspaper seven(观察者) subscribe 订阅者 有报纸即通知 feng(观察者) subscribe 订阅者 有报纸即通知 **/ #ifndef __NEWSPAPER_H__ #define __NEWSPAPER_H__ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "observer.h" /* 被观察者(报纸)类定义 */ struct newspaper { struct oble oble; /* 继承被观察者基类 */ void (*get)(struct newspaper *p_news); /* 获取报纸 */ }; /** * @创建人民日报对象 * @成功返回类对象,失败返回NULL **/ struct newspaper *new_newspaper(void); /* 观察者(订阅者)类定义 */ struct subscribe { struct ober ober; char name[16]; }; /** * @创建订阅者对象 * @name:订阅者名字 * @成功返回类对象,失败返回NULL **/ struct subscribe *new_subscribe(char *name); #endif
newspaper.c
/** * @Filename : newspaper.c * @Revision : $Revision: 1.0 $ * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅) * @Description : 观察者模式应用(C语言模拟C++) * @Explain : 报纸(被观察者) newspaper seven(观察者) subscribe 订阅者 有报纸即通知 feng(观察者) subscribe 订阅者 有报纸即通知 **/ #include "newspaper.h" /** * @获取报纸 * @p_news:报纸类 **/ static void _get_paper(struct newspaper *p_news) { p_news->oble.notify((struct oble *)p_news); } /** * @创建报纸对象 * @成功返回类对象,失败返回NULL **/ struct newspaper *new_newspaper(void) { struct oble *p_oble; struct newspaper *p_news; p_news = (struct newspaper *)malloc(sizeof(struct newspaper)); if (p_news == NULL) return NULL; memset((char *)p_news, 0, sizeof(struct newspaper)); if ((p_oble = new_oble()) == NULL) { free(p_news); return NULL; } memcpy(&(p_news->oble), p_oble, sizeof(struct oble)); free(p_oble); p_news->get = _get_paper; return p_news; } /** * @通知订阅者 * @ p_oble:被观察者类 p_ober:观察者类 **/ static void _update(struct ober *p_ober, struct oble *p_oble) { struct subscribe *p_sub = (struct subscribe *)p_ober; printf("%s : have newspaper...\n", p_sub->name); } /** * @创建订阅者对象 * @name:订阅者名字 * @成功返回类对象,失败返回NULL **/ struct subscribe *new_subscribe(char *name) { struct ober *p_ober; struct subscribe *p_sub; p_sub = (struct subscribe *)malloc(sizeof(struct subscribe)); if (p_sub == NULL) return NULL; memset((char *)p_sub, 0, sizeof(struct subscribe)); if ((p_ober = (struct ober *)malloc(sizeof(struct ober))) == NULL) { free(p_sub); return NULL; } p_ober->update = _update; memcpy(&(p_sub->ober), p_ober, sizeof(struct ober)); free(p_ober); strcpy(p_sub->name, name); return p_sub; } /** * @主函数,演示代码 **/ int main(void) { struct subscribe *p_seven = new_subscribe("seven"); struct subscribe *p_feng = new_subscribe("feng"); struct newspaper *p_news = new_newspaper(); if ((p_news == NULL) || (p_seven == NULL) || (p_feng == NULL)) { printf("create observable class failed...\n"); return -1; } /* seven 和 feng 同时订阅了人民日报 */ p_news->oble.add(&(p_news->oble), &(p_seven->ober)); p_news->oble.add(&(p_news->oble), &(p_feng->ober)); p_news->get(p_news); /* 报纸来了,seven 和 feng应同时被通知 */ printf("------------------------------\n"); /* feng 取消订阅人民日报 */ p_news->oble.rm(&(p_news->oble), &(p_feng->ober)); p_news->get(p_news); /* 报纸来了,只有seven被通知 */ return 0; }
结论
输入示例代码运行,结果如下:
feng:observer$ gcc -o newspaper newspaper.c observer.c class_dll.c dll.c feng:observer$ ./newspaper seven : have newspaper... feng : have newspaper... ------------------------------ seven : have newspaper... feng:observer$
分析:示例定义了人民日报对象作为被观察者,同时定义了seven和feng对象作为观察者,开始的时候,seven和feng均订阅了人民日报,所以当发报纸的时候,seven和feng均能收到通知,后来,feng取消订阅,所以发报纸的时候只有seven能收到通知。
往期 · 推荐
也没想象中那么神秘的数据结构-先来后到的“队列”(链式队列)
关注
更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:设计模式源码,也可点击此处下载。