观察者模式(Observer Pattern):当对象间存在一对多关系时,则使用观察者模式(ObserverPattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。
观察者模式
概要分析:
观察者模式,感觉就类似发布订阅的功能。
观察者的目标: 定义一个目标主题类,提供一个接口可以注册观察者的对象,内部管理多个。(其实也就是一个观察者的管理中心)
观察者: 定义一个基础类,可以衍生多个观察者,方便作为目标主题类接口参数。
发布者:集管理观察者的功能,有新消息时,可以主动通知。 也可以通过内部管理的观察者对象直接调用。
观察者:通过一个注册类的接口把该对象注册进去,实现有消息时通知。
源码Demo:
1:拉模型:有消息传一个主题给观察者,让观察者主动拉取
/*************************************************************************
观察者模式:
思想:自己在玩游戏,怕老板发现,自己有很担心,委托秘书来完成观察的任务,当观察到某一刻的变化时,
执行指定的任务,完成状态的切换
1.创建客户和观察者
2.客户将自己注册到观察者那里,当观察者得到某一消息时,挨个通知每个客户
3.观察者者通知携带有消息,调用客户的接收消息的函数,从而完成了所有客户的委托
这里分为两种模型:
1 直接将内容发送给各个观察者 --- 推送
2 将主题直接发送给观察者 ---拉模型
4.观察者使用一个容器来管理每个客户,从而挨个通知
***************************************************************************/
#include <iostream>
#include <list>
using namespace std;
class Subject;
class Observer
{
public:
Observer(){}
virtual ~Observer(){}
virtual void update(Subject *subject) = 0;
virtual void update(string content) = 0;
};
//注册中心
class Subject
{
public:
Subject() {}
virtual ~ Subject() {}
virtual string getContent() = 0;
virtual string getAbstractContent() = 0;
virtual void setContent(string content) = 0;
// 订阅主题
void attach(Observer *observer) {
observers.push_back(observer);
}
// 取消订阅
void detach(Observer *observer) {
observers.remove(observer);
}
// 通知所有的订阅者
virtual void notifyObservers() {
for(Observer *reader: observers) {
// 拉模型 (也是有推送的性质,只是粒度小一些)
//把主题对象推过去,让观察者自己拉取该主题内容
reader->update(this);
}
}
// 通知所有的订阅者
virtual void notifyObservers(string content) {
for(Observer *reader: observers) {
// 推模型
reader->update(content);
}
}
private:
list<Observer *> observers; // 保存注册的观察者
};
//观察者 订阅者 主动拉取关注的内容
class Reader : public Observer
{
public:
Reader() {}
virtual ~Reader() {}
virtual void update(Subject *subject) {
// 调用对应的方法去拉取内容 subject->getContent()
cout << m_name << "收到报纸和阅读它, 具体内容" << subject->getContent() << endl;
}
virtual void update(string content) {
// 推模型
cout << m_name << "收到报纸和阅读它, 具体内容" << content << endl;
}
string getName() {
return m_name;
}
void setName(string name) {
m_name = name;
}
private:
string m_name;
};
//观察者的目标 发布者
class NewsPaper: public Subject
{
public:
NewsPaper() {}
virtual ~NewsPaper() {}
void setContent(string content) {
m_content = content;
notifyObservers();
}
virtual string getContent() {
return m_content;
}
virtual string getAbstractContent() {
return "摘要:";
}
private:
string m_content;
};
int main()
{
// 创建一个报纸主题
NewsPaper *subject = new NewsPaper();
// 创建观察者,读者
Reader *reader1 = new Reader();
reader1->setName("reader1");
Reader *reader2 = new Reader();
reader2->setName("reader2");
Reader *reader3 = new Reader();
reader3->setName("reader3");
subject->attach(reader1);
subject->setContent("notifyObservers - 1");
cout << "-----------------------" << endl;
subject->attach(reader2);
subject->attach(reader3);
subject->setContent("notifyObservers -1 -2 -3 ");
delete reader1;
delete reader2;
delete reader3;
delete subject;
return 0;
}
2:推模型: 有消息直接发送
// 示例2: 推送模型 主题类中保存所有订阅者 有消息主动推送
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Secretary;
class PlayserObserver//玩游戏的同事类(观察者)
{
public:
PlayserObserver(string name)//通过构造函数完成观察者的初始化
{
m_name = name;
}
void update(string action)
{
cout << m_name << ": 收到:" << action << endl;
}
private:
string m_name;
};
class Secretary//秘书类(主题对象,通知者)
{
public:
void addObserver(PlayserObserver *o)
{
v.push_back(o);
}
void Notify(string action)
{
for (vector<PlayserObserver *>::iterator it = v.begin(); it != v.end(); it++)
{
(*it)->update(action);//这里是一个推的模型
}
}//此处容器拥有观察者对象的指针,然后带着参数去遍历不同观察者的统一接口的接受函数,显示接受到此消息
private:
vector<PlayserObserver *> v;
};
//注册进去 主动注册 有消息主动推送
int main()
{
Secretary *s1 = new Secretary; //subject 被观察者
PlayserObserver *po1 = new PlayserObserver("小张");//具体的观察者 被通知对象
PlayserObserver *po2 = new PlayserObserver("小李");
s1->addObserver(po1);//将其放进通知队列
s1->addObserver(po2);
s1->Notify("老板来了");//此处的通知函数是带有参数的
delete po1;
delete po2;
delete s1;
return 0;
}