C++中的观察者模式
前言
最近在看ETH的开源库towr时,学习到一种多个类之间有意思的用法,称为观察者模式,在这里简要记录。
一、观察者模式是什么?
观察者模式中,定义了一种一对多的依赖关系,可以让多个观察者对象同时监听某一被观察者对象,一旦被观察者状态发生变化,则相应的观察者收到通知,并发生相应的变化.通俗来讲有点"发布–订阅"的意思.其中主要有四中类:
抽象被观察者类:提供维护一个将多个观察者聚集的方法,进行观察者的增加和删除
具体被观察者类:存储有关状态,并在状态变化时,给与其相关的观察者发出通知,进行更新
抽象观察者类:为具体观察者提供一个状态更新的接口
具体观察者类:根据自身情况更新状态(可以有多个)
一个具体被观察者类对应多个具体观察者,如下图所示.抽象被观察者类与观察类之间存在双向关联关系.
二、简单例子
在这里借用其他人的例子来解释下,具体怎么实现.这里定义一个北京时间类,当作被观察者对象;然后定义美国,巴黎等时间.实现北京时间改变的同时,美国和巴黎时间自动更新.
1.抽象观察者类
/*observer.h
*首先定义一个观察者抽象类Observer,其中要声明有被观察者类Subject存在.
*/
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
class Subject; //声明存在一个Subject类
class Observer //观察者
{
public:
virtual void update(Subject * subject) = 0; //为具体的观察者对象留的更新接口
int _hour;
int _min;
int _sec;
Subject * _subject; //相联系的被观察者
};
2.抽象被观察者类
/*subject.h
*定义被观察者抽象类Subject
*/
#include"observer.h"
class Subject //被观察者
{
public:
void addRegister(Observer * observer) // 观察者注册,增加观察者
{
observerList.push_back(observer);
}
void delRegister(Observer * observer) // 观察者取消,删除观察者
{
observerList.erase(find(observerList.begin(),observerList.end(),observer));
}
void notify() //通知观察者进行更新
{
list<Observer*>::iterator itr;
for(itr = observerList.begin(); itr != observerList.end(); ++itr)
{
(*itr)->update(this);
}
}
int _hour;
int _min;
int _sec;
list<Observer*> observerList; //注册后的观察者集合
};
3.具体被观察者和观察者类
/*spline.h
*定义具体的被观察者和观察者
*/
#include"observer.h"
#include"subject.h"
class ChinaClock:public Subject //被观察者子类 北京时间
{
public:
void set(int hour, int min, int sec)
{
cout<<"China clock is set"<<endl;
_hour = hour;
_min = min;
_sec = sec;
notify(); //被观察者发出通知
}
};
class AmericaClock:public Observer //观察者子类 美国时间
{
public:
AmericaClock(Subject * subject) //将自身与被观察者关联
{
_subject = subject;
_subject->addRegister(this);
}
void update(Subject * subject) //收到通知后进行相应的更新
{
_hour = subject->_hour;
_min = subject->_min;
_sec = subject->_sec;
dis();
}
void dis()
{
cout<<"America clock is set"<<endl;
cout<<"hour:"<<_hour<<"min:"<<_min<<"sec:"<<_sec<<endl;
}
};
class LondenClock:public Observer //观察者子类 英国时间
{
public:
LondenClock(Subject * subject)
{
_subject = subject;
_subject->addRegister(this);
}
void update(Subject * subject)
{
_hour = subject->_hour;
_min = subject->_min;
_sec = subject->_sec;
dis();
}
void dis()
{
cout<<"Londen clock is set"<<endl;
cout<<"hour:"<<_hour<<"min:"<<_min<<"sec:"<<_sec<<endl;
}
};
4.主函数
int main()
{
ChinaClock *cc = new ChinaClock; //创建北京时间被观察对象
AmericaClock *ac = new AmericaClock(cc); //创建美国时间观察对象
LondenClock *lc = new LondenClock(cc); //创建英国时间观察对象
JapanClock *jc = new JapanClock(cc); //创建日本时间观察对象
cc->set(1,2,3); //改变被观察北京时间
return 0;
}
三、总结
其中重要的部分主要有:1.在观察者的构造函数中需要以被观察指针为形参,建立两者的关联;2.被观察者中需要有通知观察者的方法.