Obsever与Pub-Sub的区别(使用C++代码理解)

Observer就是观察者模式,Pub-Sub就是发布订阅模式,这2种模式有点类似,容易弄混,下面来简单看下他们的区别。


一 区别

下面这张图可以很好的展示这2者的区别
在这里插入图片描述
左边是观察者模式,右边是发布订阅模式,可以看出最大区别是发布订阅模式中间多了一个Event channel。

维基百科定义对Observer模式的定义如下,

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

一个subject可以被多个观察者观察,当subject里的某个状态发生了变化,就会去通知观察者,比较简单。

对Pub-Sub模式的定义如下,

In the pub-sub pattern, senders of messages (called publishers) do not send messages directly to specific receivers (called subscribers). There is an intermediate component, called broker, (or message broker, event bus), to which data is sent by publisher and from where data is received by subscribers. It filters all incoming messages and distributes them accordingly. The popular methods of message filtering are topic-based and content-based.

发布订阅模式中,发布者和订阅者之间是异步通信且松耦合

这两种模式具体区别有以下三点,

  • 在观察者模式中,subject知道有那些观察者,无需代理;在发布订阅模式中,发布者和订阅者互相不知道对方的存在,双方通过代理(broker)进行连接
  • 观察者模式大部分都是同步的,当某个事件或状态发生变化,会及时通知观察者,反应迅速;发布订阅模式则是异步的。
  • 观察者模式通常都是存在于一个单应用中;发布订阅模式则是应用在cross-application,用于解耦,例如微信公众号,你手机里的微信程序和公众号博主手机里的微信程序之间进行通信。

二 C++代码

下面使用C++代码去进一步理解这2种模式的区别。

1. Observer模式
#include <iostream>
#include <vector>

// Observer的接口类
class IObserver
{
    
    
public:
    virtual void update() = 0;
};


class Obs : public IObserver
{
    
    
public:
    Obs(int data) : m_data(data) 
    {
    
    }
    virtual ~Obs() {
    
    }

    virtual void update()
    {
    
    
        std::cout << "data is " << m_data << "\n";
    }

private:
    int m_data;
};

class Subject
{
    
    
public:
    Subject() : m_state(false), m_cnt(0)
    {
    
    }
    
    // 用于注册观察者
    void registerObserver(IObserver *obs)
    {
    
    
        m_allObserver.push_back(obs);
    }

    void run(void)
    {
    
    
        if (isStateChange())
        {
    
    
            for (auto one : m_allObserver)
            {
    
    
                one->update();
            }
        }
    }

private:
    bool isStateChange(void)
    {
    
    
        if ((++m_cnt) == 10000)
        {
    
    
            m_cnt = 0;
            m_state = (m_state ? false : true); 
            return true;
        }
        else
        {
    
    
            return false;
        }
        
    }

private:
    
    std::vector<IObserver *> m_allObserver;
    bool m_state;
    int m_cnt;
};


int main()
{
    
    
    Subject sub;

    Obs obs1(100);
    Obs obs2(200);
    Obs obs3(300);

    sub.registerObserver(&obs1);
    sub.registerObserver(&obs2);
    sub.registerObserver(&obs3);

    while (true)
    {
    
    
        sub.run();
    }

    return 0;
}

编译命令:

扫描二维码关注公众号,回复: 12504281 查看本文章
g++ main.cpp -std=c++11 -o main
2. Pub-Sub模式
#include <iostream>
#include <vector>

class ISubscriber;
class IPublisher;
class IBroker;

// 订阅者的接口类
class ISubscriber
{
    
    
public:
    // 向代理进行订阅
    virtual void subscribeToBroker(IBroker * ptr, std::string topic) = 0;
    
    // 当代理收到发布者的通知,就调用这个函数来通知订阅者
    virtual void updateCallback(int newVal) = 0;
};

// 发布者的接口类
class IPublisher
{
    
    
public:
    // 注册一个代理
    virtual void registerBroker(IBroker * pBroker) = 0;
    
    // 通知代理某个topic上出现新值
    virtual void publishToBroker(std::string topic, int newData) = 0;
    
    // 发布者的更新函数
    virtual void update(void) = 0;
};

// 代理的接口类
class IBroker
{
    
    
public:
    // 添加订阅者
    virtual void addSubscriber(ISubscriber * ptr, std::string topic) = 0;
    
    // 向发布者进行注册
    virtual void registerToPublisher(IPublisher * ptr) = 0;
    
    // 当发布者通知代理时,调用此函数
    virtual void onPublish(std::string topic, int newData) = 0;

};

class Broker : public IBroker
{
    
    
public:
    Broker() {
    
    }
    ~Broker() {
    
    }

    virtual void addSubscriber(ISubscriber * ptr, std::string topic)
    {
    
    
        if (topic == "AA")
        {
    
    
            m_subscriberForAA.push_back(ptr);
        }
        else if (topic == "BB")
        {
    
    
            m_subscriberForBB.push_back(ptr);
        }
        
    }

    virtual void registerToPublisher(IPublisher * ptr)
    {
    
    
        ptr->registerBroker(this);
    }

    virtual void onPublish(std::string topic, int newData)
    {
    
    
        if (topic == "AA")
        {
    
    
            for (auto one : m_subscriberForAA)
            {
    
    
                one->updateCallback(newData);
            }
        }

        else if (topic == "BB")
        {
    
    
            for (auto one : m_subscriberForBB)
            {
    
    
                one->updateCallback(newData);
            }
        }
    }

private:
    IPublisher * m_pPublisher;
    std::vector<ISubscriber *> m_subscriberForAA;
    std::vector<ISubscriber *> m_subscriberForBB;
};


class Subscriber : public ISubscriber
{
    
    
public:
    Subscriber() {
    
    }
    virtual ~Subscriber() {
    
    }

    virtual void subscribeToBroker(IBroker * ptr, std::string topic)
    {
    
    
        m_topic = topic;
        ptr->addSubscriber(this, topic);
    }

    virtual void updateCallback(int newData)
    {
    
    
        std::cout << "new data for topic " << m_topic <<  " is " << m_data << "\n";
        m_data = newData;
    }

private:
    int m_data;
    std::string m_topic;
};

class Publisher : public IPublisher
{
    
    
public:
    Publisher() : m_dataForAA(0), m_dataForBB(0), 
        m_cntForAA(0), m_cntForBB(0),
        m_brokerPtr(nullptr)
    {
    
    }

    virtual ~Publisher() {
    
    }

    virtual void registerBroker(IBroker * pBroker)
    {
    
    
        m_brokerPtr = pBroker;
    }

    virtual void publishToBroker(std::string topic, int newData)
    {
    
    
        m_brokerPtr->onPublish(topic, newData);
    }

    virtual void update(void)
    {
    
    
        if ((++m_cntForAA) == 100000)
        {
    
    
            m_cntForAA = 0;
            m_dataForAA += 10;

            publishToBroker("AA", m_dataForAA);
        }


        if ((++m_cntForBB) == 200000)
        {
    
    
            m_cntForBB = 0;
            m_dataForBB += 20;

            publishToBroker("BB", m_dataForBB);
        }
    }

private:
    int m_dataForAA;
    int m_dataForBB;

    int m_cntForAA;
    int m_cntForBB;

    IBroker * m_brokerPtr;
};



int main()
{
    
    
    Broker broker;
    Publisher pub;
    broker.registerToPublisher(&pub);

    Subscriber sub1;
    Subscriber sub2;
    Subscriber sub3;
    Subscriber sub4;

    sub1.subscribeToBroker(&broker, "AA");
    sub2.subscribeToBroker(&broker, "AA");
    sub3.subscribeToBroker(&broker, "BB");
    sub4.subscribeToBroker(&broker, "BB");


    while (true)
    {
    
    
        pub.update();
    }

    return 0;
}

编译命令:

g++ main.cpp -std=c++11 -o main

猜你喜欢

转载自blog.csdn.net/whahu1989/article/details/111131005