概念
观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
注意
1、对于观察者模式,包含被观察者(有且只有一个)和观察者(一般为多个)两类对象。
2、观察者对象管理可采用数组和链表两种方式进行管理。
数组管理:定义时必须先确定大小,并且不可改变,所以管理起来相对不够灵活,优点是操作简单。
链表管理:有很强的灵活性,缺点是操作比较麻烦,对于基础稍差的小伙伴不是那么友好。
建议采用链表的方式管理,若对链表操作不是那么懂的小伙伴可翻阅《也没想象中那么神秘的数据结构-通用链表设计方法》,有现成的代码,可以直接使用。
介绍
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
关键代码:在抽象类里有一个线性表存放观察者们。
核心
定义被观察者对象,并在对象里面定义线性表存放所有观察者对象,当被观察者状态改变时,遍历然后通知所有观察者对象,这种模式有点类似广播。
示例
★被观察者对象:
属性:观察者管理链 (包含所有添加的观察者,因为涉及到增加删除较多,建议使用链表的方式管理)
行为:增加观察者、删除观察者、通知观察者。
★观察者对象:
属性:无
行为:更新数据(在实际对象中实例化)。
★包含头文件observer.h和源文件observer.c(均已验证通过)。
observer.h
/** * @Filename : observer.h * @Revision : $Revision: 1.0 $ * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅) * @Description : 观察者模式基类实现(C语言模拟C++) * @Explain : 包含两个基类 observable(被观察者) observer(观察者) 以下使用简称 oble = observable ober = observer **/ #ifndef __OBSERVER_H__ #define __OBSERVER_H__ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "dll.h" #include "class_dll.h" struct oble; /* 被观察者类 */ struct ober; /* 观察者类 */ /* 类操作, 带参数 */ #define CLASS_CALL(THIS,func,args...) ((THIS)->func(THIS,args)) /* 类操作, 无参数 */ #define CLASS_CALL_0(THIS,func) ((THIS)->func(THIS)) /* 节点定义, 使用链表管理观察者 */ struct t_ober_node { struct t_node node; struct ober *p_ober; }; /* 观察者类定义 ober = class observer */ struct ober { void (*update)(struct ober *p_ober, struct oble *p_oble); /* 数据更新 */ }; /* 被观察者类定义 oble = class observable */ struct oble { struct dll *p_ober_dll; /* 观察者链 */ int (*add)(struct oble *p_oble, struct ober *p_ober); /* 添加观察者 */ void (*rm)(struct oble *p_oble, struct ober *p_ober); /* 移除观察者 */ void (*notify)(struct oble *p_oble); /* 通知观察者 */ }; /** * @创建被观察者对象 * @成功返回被观察者类地址,失败返回NUL **/ struct oble *new_oble(void); #endif
observer.c
/** * @Filename : observer.c * @Revision : $Revision: 1.0 $ * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅) * @Description : 观察者模式基类实现(C语言模拟C++) * @Explain : 包含两个基类 observable(被观察者) observer(观察者) 以下使用简称 oble = observable ober = observer **/ #include "observer.h" /** * @判断节点中是否包含指定信息,用于链表创建,后续查找使用 * @node:节点 key:指定信息 * @包含返回0,否则返回-1 **/ static int _cmp_key(struct t_node *node, void *key) { struct t_ober_node *p_node = NULL; if ((node == NULL) || (key == NULL)) return -1; p_node = (struct t_ober_node *)node; return (p_node->p_ober == (struct ober *)key ? 0 : -1); } /** * @添加观察者 * @p_oble:被观察者类 p_ober:观察者类 * @包含返回0,否则返回-1 **/ static int _add_ober(struct oble *p_oble, struct ober *p_ober) { struct t_ober_node *p_node = NULL; if ((p_oble == NULL) && (p_ober == NULL)) { printf("parameter error...\n"); return -1; } if (NULL != CLASS_CALL(p_oble->p_ober_dll, find_key, p_ober)) { printf("the obsever is already exit...\n"); return 0; } if ((p_node = (struct t_ober_node *)malloc(sizeof(struct t_ober_node))) == NULL) { printf("malloc node error...\n"); return -1; } p_node->p_ober = p_ober; CLASS_CALL(p_oble->p_ober_dll, add, (struct t_node *)p_node); return 0; } /** * @移除观察者 * @p_oble:被观察者类 p_ober:观察者类 **/ static void _rm_ober(struct oble *p_oble, struct ober *p_ober) { CLASS_CALL(p_oble->p_ober_dll, del_key, p_ober); } /** * @通知观察者 * @p_oble:被观察者类 **/ static void _notify_ober(struct oble *p_oble) { struct t_ober_node *p_node = NULL; if (p_oble == NULL) { printf("parameter error...\n"); return; } p_node = (struct t_ober_node *)CLASS_CALL_0(p_oble->p_ober_dll, get_first); while (p_node != NULL) { p_node->p_ober->update(p_node->p_ober, p_oble); p_node = (struct t_ober_node *)p_oble->p_ober_dll->get_next((struct t_node *)p_node); } } /** * @创建被观察者对象 * @成功返回被观察者类地址,失败返回NUL **/ struct oble *new_oble(void) { struct dll *p_dll; struct oble *p_oble = (struct oble *)malloc(sizeof(struct oble)); if (p_oble == NULL) return NULL; memset((char *)p_oble, 0, sizeof(struct oble)); if ((p_dll = new_dll(_cmp_key, NULL)) == NULL) { free(p_oble); return NULL; } p_oble->p_ober_dll = p_dll; p_oble->add = _add_ober; p_oble->rm = _rm_ober; p_oble->notify = _notify_ober; return p_oble; }
结论
本示例只提供了观察者模式的基类定义,后期验证还需要根据实际应用创建被观察者和观察者对象,加入具体应用逻辑代码,方可验证,本公众号也提供两种应用场景来验证此设计模式的有效性,请参见《我用C语言玩对象,观察者模式应用1-订报》和《我用C语言玩对象,观察者模式应用2-热水的用途》。
往期 · 推荐
也没想象中那么神秘的数据结构-先来后到的“队列”(链式队列)
也没想象中那么神秘的数据结构-先来后到的“队列”(循环队列)
我用C语言玩对象,框架化的模板模式
关注
更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:设计模式源码,也可点击此处下载。
本文介绍了观察者模式,它定义了一对多依赖关系,主题对象状态变化时会通知观察者。包含被观察者和观察者两类对象,观察者管理可采用数组或链表,建议用链表。给出了被观察者和观察者对象的属性与行为示例,还提供了相关头文件和源文件。

4167

被折叠的 条评论
为什么被折叠?



