行为型 观察者模式(发布订阅)

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

猜你喜欢

转载自blog.csdn.net/yun6853992/article/details/119132751