观察者模式(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; }