0. 简介

个人认为观察者模式作为行为模式中非常重要的一个部分,我们日常使用的事件机制就是一个观察者模式,当事件发生,所有的事件接收者执行事件响应函数。在ROS中的subscribers函数也是使用了类似的思想。它允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。

1. 订阅者模式示意图

从ROS的Topic层面理解,拥有一些值得关注的状态的对象通常被称为目标, 由于它要将自身的状态改变通知给其他对象, 我们也将其称为发布者 (publisher)。 所有希望关注发布者状态变化的其他对象被称为订阅者 (subscribers)

观察者模式建议你为发布者类添加订阅机制, 让每个对象都能订阅或取消订阅发布者事件流。该机制包括:

  1. 一个用于存储订阅者对象引用的列表成员变量;
  2. 几个用于添加或删除该列表中订阅者的公有方法。
    在这里插入图片描述
    从图中我们可以看到,通过发布和订阅的机制可以有效的实现触发的方式,相比于传统的主动触发观察者模式,使用回调函数去完成观察者的时间监听触发是一个更好的选择。
    在这里插入图片描述

2. 示例代码

2.1 普通的触发

这部分的内容没有使用回调函数去完成触发,通过调用来实现函数的使用

#include <iostream>
#include <set>


using namespace std;

//观察者接口,包括事件响应函数
class Observer
{
public :
    virtual void update(int n)=0;
};

//目标类,负责触发事件
class Subject
{
public:
    Subject(){};
    //添加事件监听
    void addObserver(Observer *observer)
    {
        observerSet.insert(observer);
    }
    //删除事件监听
    void removeObserver(Observer *observer)
    {
        observerSet.erase(observer);
    }
    //触发事件
    void notify(int n)
    {
        set<Observer *>::iterator iter;
        for(iter = observerSet.begin() ; iter != observerSet.end() ; ++iter)
        {
            (*iter)->update(n);
           // iter.   ->update();
        }
    }


private:
    set<Observer *> observerSet;
};

class Observer1 :public Observer
{
public:
    void update(int n)
    {
        cout<<"观察者1事件响应函数,接受参数:"<<n<<endl;
    }

};
class Observer2 :public Observer
{
public:
    void update(int n)
    {
        cout<<"观察者2事件响应函数,接受参数:"<<n<<endl;
    }

};
main()
{
    Subject subject;
    Observer * observer1 = new   Observer1();
    Observer * observer2 = new   Observer2();
    subject.addObserver(observer1);
    subject.addObserver(observer2);
    subject.notify(4);
    subject.notify(1);


}

2.2 回调函数触发

这部分通过模板类来实现函数的调用,通过operator()来调用invoke函数实现回调触发。


/* 实现事件的信号类 */
template <typename... TFuncArgs>
class Signal {
public:
    using Callback = std::function<void(TFuncArgs...)>;

    /* 连接类, 一旦结束,Disconnect()将被自动调用。  
    */
    class SignalConnection {
    private:
        friend class Signal;
        /* 只允许类Signal创建连接 */
        SignalConnection(Signal& signal, int id) noexcept:id(id), signal(signal) {}
    public:
        /*  C++11 成员函数声明新特性: = delete,从逻辑语义上禁止了对于SignalConnection类拷贝构造函数和赋值运算符*/
        SignalConnection(const SignalConnection& copy) = delete;
        /* 如果没有复制构造函数,则不能返回SignalConnection,除非提供一个move构造函数。 */
        SignalConnection(SignalConnection&& toMove) noexcept : id(toMove.id), signal(toMove.signal),disconnected(toMove.disconnected) {}
        ~SignalConnection() {
            Disconnect();
        }
        int id;
        Signal& signal;
        bool disconnected = false;
        void Disconnect() {
            if (disconnected)
                return;
            disconnected = true;
            signal.Disconnect(*this);
        }
    };

    /* 返回连接对象,连接对象一旦超出作用域将自动断开连接 */
    SignalConnection Connect(Callback callback) {
        callbacks.push_back(std::pair<int, Callback>(idRoller++, callback));
        return SignalConnection(*this, idRoller - 1);
    }

    void Invoke(TFuncArgs... args) {
        for (auto& con : callbacks) {
            (con.second)(args...);
        }
    }

    void operator()(TFuncArgs... args) {
        Invoke(args...);
    }

private:
    /* ID Counter.
    使用id查找连接对应的回调函数,因为std::function的操作符==并不像想象的那样工作。*/
    int idRoller = 0;
    std::list<std::pair<int, Callback>> callbacks;

    void Disconnect(SignalConnection& t) {
        callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(), [&](auto& pCallback) {
            return pCallback.first == t.id;
        }), callbacks.end());
    }
};


void TestFunc1(int t) {
    cout << "Func1" << endl;
}
void TestFunc2(int t,string someArg) {
    cout << "Func2" << endl;
}

int main(){
    using TestDelegate = Signal<int>;    
    TestDelegate testEvent;
    TestDelegate::SignalConnection testCon1 = testEvent.Connect(&TestFunc1);    
    TestDelegate::SignalConnection testCon2 = testEvent.Connect(std::bind(TestFunc2 ,std::placeholders::_1, "arg"));  //用bind去绑定参数
    auto testCon3 = testEvent.Connect(&TestFunc1);        //用auto简化声明
    testEvent(1);
...

3. 参考链接

https://blog.csdn.net/tm8426/article/details/73472496

https://refactoringguru.cn/design-patterns/observer/cpp/example#lang-features

https://www.cnblogs.com/hebaichuanyeah/p/6091694.html

https://blog.csdn.net/liukang325/article/details/44461449

https://www.cnblogs.com/yangrouchuan/p/7817773.html

http://c.biancheng.net/view/1390.html

https://www.cnblogs.com/duanxz/p/9877928.html