行为型设计模式之观察者模式:
一、含义
观察者模式也叫做发布订阅模式,定义对象间一种一对多的依赖关系,
每当一个对象改变状态(被观察者),则所有依赖于它的对象(观察者)都会得到通知并被自动更新
即被观察者对应状态产生时,会通知所有的观察者,同时观察者被自动更新。
二、代码说明
1.主要有两个角色
1)被观察者
它必须能够动态地增加、取消观察者,并且状态改变时会通知观察者(这三个个必须有的操作抽象出来),
同时被观察也有自己的业务逻辑,定义对哪些事件进行通知
2)观察者
观察者接收到消息后,即进行update(更新方法)操作(抽象出来),对接收到的信息进行处理。
每个观察者接收到消息后的处理反应是不同,各个观察这个有自己的处理逻辑
2.在用C实现过程中也是参考这种思想,不过由于C的局限,使用继承(覆写)代替实现两个接口更好。
以李斯观察韩非子为例,具体实现如下:
1)观察者模式使用场景:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : ObserverPatternUsage.c 5 * Description : 观察者模式的使用 6 7 book@book-desktop:/work/projects/test/DesignPatterns/ObserverPattern$ gcc -o ObserverPatternUsage ObserverLisi.c ObserverWangsi.c ObserverPattern.c ObserverPatternUsage.c 8 book@book-desktop:/work/projects/test/DesignPatterns/ObserverPattern$ ./ObserverPatternUsage 9 韩非子:开始吃饭... 10 李斯:观察到韩非子活动,开始向秦老板汇报 11 李斯:报告,秦老板,韩非子有活动了-->韩非子在吃饭 12 李斯:汇报完毕... 13 王斯:观察到韩非子活动,自己也开始活动了... 14 王斯:因为韩非子在吃饭,所以我悲伤啊 15 王斯:哭死了... 16 韩非子:开始娱乐了... 17 李斯:观察到韩非子活动,开始向秦老板汇报 18 李斯:报告,秦老板,韩非子有活动了-->韩非子在娱乐 19 李斯:汇报完毕... 20 21 * Created : 2017.07.13. 22 * Author : Yu Weifeng 23 * Function List : 24 * Last Modified : 25 * History : 26 ******************************************************************************/ 27 #include"stdio.h" 28 #include"malloc.h" 29 #include"stdlib.h" 30 #include"string.h" 31 #include"ObserverPattern.h" 32 33 34 35 36 /***************************************************************************** 37 -Fuction : main 38 -Description : 39 -Input : 40 -Output : 41 -Return : 42 * Modify Date Version Author Modification 43 * ----------------------------------------------- 44 * 2017/07/13 V1.0.0 Yu Weifeng Created 45 ******************************************************************************/ 46 int main(int argc,char **argv) 47 { 48 T_Observer Lisi=newLisiObserver; 49 T_Observer Wangsi=newWangsiObserver; 50 51 T_Observable tObserver=newHanfeiziObservable; 52 T_Hanfeizi Hanfeizi=newHanfeizi(&tObserver); 53 54 Hanfeizi.ptObservable->AddObserver(&Lisi); 55 Hanfeizi.ptObservable->AddObserver(&Wangsi); 56 Hanfeizi.HaveBreakfast(); 57 58 Hanfeizi.ptObservable->DeleteObserver(&Wangsi); 59 Hanfeizi.HaveFun(); 60 61 62 return 0; 63 }
2)被调用者:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : ObserverPattern.c 5 * Description : 观察者模式 6 本文件是被观察者实现类 7 以韩非子的活动被李斯,王斯观察举例,显然 8 韩非子是被观察者 9 * Created : 2017.07.13. 10 * Author : Yu Weifeng 11 * Function List : 12 * Last Modified : 13 * History : 14 ******************************************************************************/ 15 #include"stdio.h" 16 #include"malloc.h" 17 #include"stdlib.h" 18 #include"string.h" 19 #include"ObserverPattern.h" 20 21 22 static T_Observer g_atObserver[MAX_OBSERVER_NUM]={NULL}; 23 static int g_iObserverLen=0; 24 25 /***************************************************************************** 26 -Fuction : HanfeiziAddObserver 27 -Description : 公有函数 28 -Input : 29 -Output : 30 -Return : 31 * Modify Date Version Author Modification 32 * ----------------------------------------------- 33 * 2017/07/13 V1.0.0 Yu Weifeng Created 34 ******************************************************************************/ 35 int HanfeiziAddObserver(T_Observer *i_ptObserver) 36 { 37 int iRet=-1; 38 if(g_iObserverLen>=MAX_OBSERVER_NUM) 39 { 40 printf("ObserverArray full! "); 41 iRet=-1; 42 } 43 else 44 { 45 memcpy(&g_atObserver[g_iObserverLen],i_ptObserver,sizeof(T_Observer)); 46 g_iObserverLen++; 47 //printf("ObserverLen:%d ",g_iObserverLen); 48 iRet=0; 49 } 50 return iRet; 51 } 52 /***************************************************************************** 53 -Fuction : HanfeiziAddObserver 54 -Description : 公有函数 55 -Input : 56 -Output : 57 -Return : 58 * Modify Date Version Author Modification 59 * ----------------------------------------------- 60 * 2017/07/13 V1.0.0 Yu Weifeng Created 61 ******************************************************************************/ 62 int HanfeiziDeleteObserver(T_Observer *i_ptObserver) 63 { 64 int iRet=-1; 65 int i; 66 if(g_iObserverLen==0) 67 { 68 printf("ObserverArray empty! "); 69 iRet=-1; 70 } 71 else 72 { 73 for(i=0;i<g_iObserverLen;i++) 74 { 75 if(0==memcmp(&g_atObserver[i],i_ptObserver,sizeof(T_Observer))) 76 { 77 break; 78 } 79 else 80 { 81 } 82 } 83 if(i>=g_iObserverLen) 84 { 85 printf("HanfeiziDeleteObserver err! "); 86 iRet=-1; 87 } 88 else 89 { 90 for(;i<g_iObserverLen-1;i++) 91 { 92 memcpy(&g_atObserver[i],&g_atObserver[i+1],sizeof(T_Observer)); 93 } 94 g_iObserverLen--; 95 iRet=0; 96 } 97 } 98 return iRet; 99 } 100 101 /***************************************************************************** 102 -Fuction : HanfeiziNotifyObservers 103 -Description : 公有函数 104 -Input : 105 -Output : 106 -Return : 107 * Modify Date Version Author Modification 108 * ----------------------------------------------- 109 * 2017/07/13 V1.0.0 Yu Weifeng Created 110 ******************************************************************************/ 111 void HanfeiziNotifyObservers(char *i_strContext) 112 { 113 int i; 114 for(i=0;i<g_iObserverLen;i++) 115 {//通知所有观察这 116 g_atObserver[i].Update(i_strContext); 117 } 118 } 119 120 121 /***************************************************************************** 122 -Fuction : HanfeiziHaveBreakfast 123 -Description : 公有函数 124 -Input : 125 -Output : 126 -Return : 127 * Modify Date Version Author Modification 128 * ----------------------------------------------- 129 * 2017/07/13 V1.0.0 Yu Weifeng Created 130 ******************************************************************************/ 131 void HanfeiziHaveBreakfast() 132 { 133 printf("韩非子:开始吃饭... "); 134 //通知所有观察者 135 HanfeiziNotifyObservers("韩非子在吃饭"); 136 } 137 138 /***************************************************************************** 139 -Fuction : HanfeiziHaveFun 140 -Description : 公有函数 141 -Input : 142 -Output : 143 -Return : 144 * Modify Date Version Author Modification 145 * ----------------------------------------------- 146 * 2017/07/13 V1.0.0 Yu Weifeng Created 147 ******************************************************************************/ 148 void HanfeiziHaveFun() 149 { 150 printf("韩非子:开始娱乐了... "); 151 //通知所有观察者 152 HanfeiziNotifyObservers("韩非子在娱乐"); 153 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : ObserverPattern.h 5 * Description : 观察者模式 6 7 * Created : 2017.07.13. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #ifndef OBSERVER_PATTERN_H 14 #define OBSERVER_PATTERN_H 15 16 #define MAX_OBSERVER_NUM 5 17 typedef struct Observer 18 { 19 void (*Update)(char *i_strContext); 20 }T_Observer;//抽象出观察者 21 22 typedef struct Observable 23 { 24 int (*AddObserver)(T_Observer *i_ptObserver);//传参,接口,也就是抽象耦合 25 int (*DeleteObserver)(T_Observer *i_ptObserver); 26 void (*NotifyObservers)(char *i_strContext); 27 }T_Observable;//抽象出被观察者 28 29 typedef struct Hanfeizi//C的局限,使用继承(覆写)代替实现两个接口更好 30 {//(少定义一个实现类,封装性也更好) 31 T_Observable *ptObservable; 32 void (*HaveBreakfast)(); 33 void (*HaveFun)(); 34 }T_Hanfeizi; 35 36 37 int HanfeiziAddObserver(T_Observer *i_ptObserver); 38 int HanfeiziDeleteObserver(T_Observer *i_ptObserver); 39 void HanfeiziNotifyObservers(char *i_strContext); 40 void HanfeiziHaveBreakfast(); 41 void HanfeiziHaveFun(); 42 #define newHanfeiziObservable {HanfeiziAddObserver,HanfeiziDeleteObserver,HanfeiziNotifyObservers} 43 #define newHanfeizi(Observable) {Observable,HanfeiziHaveBreakfast,HanfeiziHaveFun} 44 45 46 void LisiUpdate(char *i_strContext); 47 #define newLisiObserver {LisiUpdate} 48 49 void WangsiUpdate(char *i_strContext); 50 #define newWangsiObserver {WangsiUpdate} 51 52 53 #endif
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : ObserverLisi.c 5 * Description : 观察者李斯 6 本文件是观察者实现类李斯的动作 7 * Created : 2017.07.13. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #include"stdio.h" 14 #include"malloc.h" 15 #include"stdlib.h" 16 #include"string.h" 17 #include"ObserverPattern.h" 18 19 /***************************************************************************** 20 -Fuction : LisiReportToQinshihuang 21 -Description : 私有函数 22 -Input : 23 -Output : 24 -Return : 25 * Modify Date Version Author Modification 26 * ----------------------------------------------- 27 * 2017/07/13 V1.0.0 Yu Weifeng Created 28 ******************************************************************************/ 29 static void LisiReportToQinshihuang(char *i_strContext) 30 { 31 printf("李斯:报告,秦老板,韩非子有活动了-->%s ",i_strContext); 32 } 33 34 /***************************************************************************** 35 -Fuction : LisiUpdate 36 -Description : 公有函数 37 -Input : 38 -Output : 39 -Return : 40 * Modify Date Version Author Modification 41 * ----------------------------------------------- 42 * 2017/07/13 V1.0.0 Yu Weifeng Created 43 ******************************************************************************/ 44 void LisiUpdate(char *i_strContext) 45 { 46 printf("李斯:观察到韩非子活动,开始向秦老板汇报 "); 47 LisiReportToQinshihuang(i_strContext); 48 printf("李斯:汇报完毕... "); 49 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /***************************************************************************** 2 * Copyright (C) 2017-2018 Hanson Yu All rights reserved. 3 ------------------------------------------------------------------------------ 4 * File Module : ObserverWangsi.c 5 * Description : 观察者王斯 6 本文件是观察者实现类王斯的动作 7 * Created : 2017.07.13. 8 * Author : Yu Weifeng 9 * Function List : 10 * Last Modified : 11 * History : 12 ******************************************************************************/ 13 #include"stdio.h" 14 #include"malloc.h" 15 #include"stdlib.h" 16 #include"string.h" 17 #include"ObserverPattern.h" 18 19 /***************************************************************************** 20 -Fuction : WangsiCry 21 -Description : 私有函数 22 -Input : 23 -Output : 24 -Return : 25 * Modify Date Version Author Modification 26 * ----------------------------------------------- 27 * 2017/07/13 V1.0.0 Yu Weifeng Created 28 ******************************************************************************/ 29 static void WangsiCry(char *i_strContext) 30 { 31 printf("王斯:因为%s,所以我悲伤啊 ",i_strContext); 32 } 33 34 /***************************************************************************** 35 -Fuction : WangsiUpdate 36 -Description : 公有函数 37 -Input : 38 -Output : 39 -Return : 40 * Modify Date Version Author Modification 41 * ----------------------------------------------- 42 * 2017/07/13 V1.0.0 Yu Weifeng Created 43 ******************************************************************************/ 44 void WangsiUpdate(char *i_strContext) 45 { 46 printf("王斯:观察到韩非子活动,自己也开始活动了... "); 47 WangsiCry(i_strContext); 48 printf("王斯:哭死了... "); 49 }
3)执行结果:
book@book-desktop:/work/projects/test/DesignPatterns/ObserverPattern$ gcc -o ObserverPatternUsage
ObserverLisi.c ObserverWangsi.c ObserverPattern.c ObserverPatternUsage.c
book@book-desktop:/work/projects/test/DesignPatterns/ObserverPattern$ ./ObserverPatternUsage
韩非子:开始吃饭...
李斯:观察到韩非子活动,开始向秦老板汇报
李斯:报告,秦老板,韩非子有活动了-->韩非子在吃饭
李斯:汇报完毕...
王斯:观察到韩非子活动,自己也开始活动了...
王斯:因为韩非子在吃饭,所以我悲伤啊
王斯:哭死了...
韩非子:开始娱乐了...
李斯:观察到韩非子活动,开始向秦老板汇报
李斯:报告,秦老板,韩非子有活动了-->韩非子在娱乐
李斯:汇报完毕...
4)详细代码:
https://github.com/fengweiyu/DesignThinking/tree/master/DesignPatterns/BehavioralDesignPatterns/ObserverPattern
三、使用场景
1.关联行为场景,
需要注意的是,关联行为是可拆分的,而不是"组合"关系
2.时间多级触发场景
3.跨系统的消息交换场景,如消息队列的处理机制
4.一个地方监视另外一个地方的处理情况,但又不想让监视方与被监视方之间相互依赖的时候
四、优点
1.观察者和被观察者之间是抽象耦合
2.建立了一套触发机制
五、缺点
1.一个被观察者,多个观察者,开发和调试就会比较复杂,在这种情况下,一般考虑采用异步的方式(考虑线程安全和队列的问题)。
多级触发时的效率更是让人担忧,大家在设计时注意考虑。
2.一个被观察者,多个观察者,观察者如何快速响应问题,两个办法:
1)采用多线程技术,
无论是被观察者启动线程还是观察者启动线程,都可以跳高系统性能,这也就是大家通常说的异步架构
2)缓存技术,
即准备好足够的资源,以保证快速响应,代价就是开发难度大,压力测试要足够充分,这种方法也就是大家说的同步架构
2.广播链问题
一个观察者可以有双重身份,既是观察者也是被观察者,这就会形成一个触发链。这样逻辑就比较复杂,可维护性非常差,在一个观察者模式中最多出现一个对象既是观察者也是被观察者,也就是说消息最多转发一次(传递两次)才比较好控制。
注意:它和责任链模式最大的区别是,观察者模式是相邻两个结点结构,即处理完返回时也是返回到上一个结点。而责任链处理完后可以直接返回到最初的结点即根节点。