一. 定义
观察者模式定义:当对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新,也可以称这种模式发布-订阅模式
二.应用场景
应用场景:Excel 中的数据与折线图、饼状图、柱状图之间的关系;MVC 模式中的模型与视图的关系;事件模型中的事件源与事件处理者等等
三.优缺点
主要优点有,降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系,目标与观察者之间建立了一套触发机制
当然也有缺点:当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率
所谓技术利弊两面,取决于具体应用需求
四.模式结构
观察者模式的结构如下。
-
抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的集合和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
-
抽象观察者(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");
}
六.总结
当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象有待改变的时候,应该考虑使用观察者模式,同时观察者模式所做的工作也是在解除耦合,各个对象互为独立工作。