观察者模式

这种模式比较常见,发布和订阅的机制。

普通触发

示例:

/*观察者模式*/

#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;
    }

};


int main()
{
    Subject subject;
    Observer * observer1 = new   Observer1();
    Observer * observer2 = new   Observer2();

    subject.addObserver(observer1);
    subject.addObserver(observer2);
    subject.notify(4);
    subject.notify(1);

    cout << endl;

    subject.removeObserver(observer1);
    subject.notify(5);

    getchar();
    return 0;
}

输出:

观察者1事件响应函数,接受参数:4
观察者2事件响应函数,接受参数:4
观察者1事件响应函数,接受参数:1
观察者2事件响应函数,接受参数:1

观察者2事件响应函数,接受参数:5

回调函数触发

代码:

#include <iostream>
#include <set>
#include <functional>
#include <list>
#include <algorithm>
#include <string>

using namespace std;

/* 实现事件的信号类 */
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: t = " <<  t << endl;
}

void TestFunc2(int t, string someArg) 
{
    cout << "Func2: t = " << t << " someArg = " << someArg << 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);

    getchar();
    return 0;
}

输出:

Func1: t = 1
Func2: t = 1 someArg = arg
Func1: t = 1




参考:

https://www.guyuehome.com/38658

posted @   double64  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2021-09-18 C# 集合之 ArrayList
2021-09-18 英语|你能明白我的意思吗
点击右上角即可分享
微信分享提示