定义
定义了主题对象与观察者对象之间的一对多依赖,当主题改变状态时,观察者对象都会收到通知并且自动更新
要点
- 观察者模式中的对象之间是一对多的关系
- 主题使用一个共同的接口来更新观察者
- 主题与观察者之间采用松耦合的方式结合,主题不知道观察者的细节,只知道观察者实现了某个接口
- 使用此模式时,观察者可被动等待主题的数据(更好),也可主动获取自己需要的主题的数据
类图
网上截取的
代码实现及实例
要求: 单片机程序中,检测某一输入IO口的状态,当输入为1时,向UART1、UART2发送数据,并更新液晶显示
代码实现:
假设
IO的状态为 IO_STATE
设备定义为封装好open,close,send等等操作的Device ,UART1、UART2、LCD为设备名称
抽象的观察者C代码实现:
typedef struct observer { void (*update)(); }Observer;
抽象的主题C代码实现:
#define OBSERVER_MAX_COUNT 5 typedef struct subject { Observer *array_observer[OBSERVER_MAX_COUNT]; //每个主题最多支持5个观察者 int (*register_observer)(Observer *observer); //向主题注册观察者 int (*remove_observer)(Observer *observer); //移除观察者 void (*notify_observer)(void); //通知消息 //void (*other_function)(void); //主要指观察者用来主动获取数据的函数 }Subject;
创建IO口的Subject。创建UART1、UART2、LCD的Observer,并向subject注册
Subject IO_Subject; static int observer_count=0; //记录观察者数量 int f_register_observer(Observer *observer) { if(observer_count>=OBSERVER_MAX_COUNT) return 0; IO_Subject.array_observer[observer_count++]=observer; return 1; } int f_remove_observer(Observer *observer) { int i=0; for(i=0;i<observer_count;i++) { if(observer==IO_Subject.array_observer[i]) { IO_Subject.array_observer[i]=0; break; } } return 1; } void f_notify_observer() { int i=0; Observer *observer=0; for(i=0;i<observer_count;i++) { observer=IO_Subject.array_observer[i]; if(observer!=0) observer->update(); } } void init_io_subject() { int i=0; for(i=0;i<OBSERVER_MAX_COUNT;i++) IO_Subject.array_observer[i]=0; IO_Subject.notify_observer=f_notify_observer; IO_Subject.remove_observer=f_remove_observer; IO_Subject.register_observer=f_notify_observer; } void check_and_notify() { int state=0; state=(IO_STATE?1:0); if(state==1) IO_Subject.notify_observer();
}
Observer Uart1_Observer; Observer Uart2_Observer; Observer Lcd_Observer; void init_observer(Observer *observer,void (*update)(void)) { observer->update=update; }
main中初始化及调用
void add_observer(Subject *subject,Observer *observer) { subject->register_observer(observer); } void main() { init_io_subject(); init_observer(&Uart1_Observer,UART1.send); init_observer(&Uart2_Observer,UART2.send); init_observer(&Lcd_Observer, Lcd.send); add_observer(&IO_Subject,&Uart1_Observer); add_observer(&IO_Subject,&Uart2_Observer); add_observer(&IO_Subject,&Lcd_Observer); while(1) { check_and_notify(); } }
可以看到,改变主题或者观察者其中任意一方,并不会影响另一方。当我们需要添加另一IO口时,或者动作方式改为收到某个串口数据后再更新LCD时,或者增减一个观察设备时,只需简单的实现对应的结构,在main中初始化、注册就行了