(原创)c++11改进我们的模式之改进观察者模式

和单例模式面临的是同样的问题,主题更新的接口难以统一,很难做出一个通用的观察者模式,还是用到可变模板参数解决这个问题,其次还用到了右值引用,避免多余的内存移动。c++11版本的观察者模式支持注册的观察者为函数、函数对象和lamda表达式,也避免了虚函数调用,更简洁更通用。直接看代码。

template<typename Func>
class Events
{
public:
    Events():m_nextKey(0)
    {}
    ~Events(){}

int Connect(Func&& f)

{

return Assgin(f);

}



int Connect(Func& f)

{

return Assgin(f);

}



template

int Assgin(F&& f)

{

int k=m_nextKey++;

m_connections[k]=f;

return k;

}

void Disconnect(int key)     {
        m_connections.erase(key);
    }

    template<typename... Args>
    void Notify(Args&&... args)
        {
        for (auto& it: m_connections)
        {
            it.second(std::forward<Args>(args)...);
        }
    }

private:
    int m_nextKey;
    std::map<int, Func> m_connections;
};

测试代码:

struct stA { int a, b; };
void print(int a, int b) { cout << a << ", " << b << endl; }
void TestObserver()
{
    Events<std::function<void(int,int)>> myevent;

    auto key=myevent.Connect(print); //以函数方式注册观察者
    stA t;
    auto lambdakey=myevent.Connect([&t](int a, int b){ t.a=a; t.b=b; });//lamda注册

    int a=1,b=2;
    myevent.Notify(a,b); //广播所有观察者
    myevent.Disconnect(key); //移除观察者

}

/****更新,增加+=和-=运算符重载,使用法和c#的event的用法接近。

#include <map>
template<typename Func>
class Events : NonCopyable
{
public:
    Events() :m_nextKey(0)
    {}
    ~Events(){}


    int operator += (Func&& f)
    {
        return Connect(std::forward<Func>(f));
    }

    int operator += (Func& f)
    {
        return Connect(f);
    }

    template<typename... Args>
    void operator()(Args&&... args)
    {
        Notify(std::forward<Args>(args)...);
    }

    Events& operator -= (int key)
    {
        Disconnect(key);
        return *this;
    }

    void Clear()
    {
        m_connections.clear();
    }

private:
    int Connect(Func&& f)
    {
        return Assgin(std::forward<Func>(f));
    }

    int Connect(Func& f)
    {
        return Assgin(f);
    }

    void Disconnect(int key)
    {
        m_connections.erase(key);
    }

    template<typename... Args>
    void Notify(Args&&... args)
    {
        for (auto& it : m_connections)
        {
            it.second(std::forward<Args>(args)...);
        }
    }

    template<typename F>
    int Assgin(F&& f)
    {
        int index = m_nextKey++;
        Push(index, std::forward<Func>(f));
        return index;
    }

    template<typename F>
    void Push(int index, F&& f)
    {
        m_connections.emplace(index, std::move(f));
    }

    template<typename F>
    void Push(int index, F& f)
    {
        m_connections.emplace(index, f);
    }

private:
    int m_nextKey;
    std::map<int, Func> m_connections;
};

测试代码:

struct stA { 
    int a;
    int b;
    void fun(int x, int y)
    {
        a = x;
        b = y;
        cout << "a = " << a << " b= " << b << endl;
    }
};
void print(int a, int b) { cout << a << ", " << b << endl; }
void TestEvent()
{
    using Delegate1 = std::function<void(int, int)>;
    using Event1 = Events<Delegate1>;
    Event1 evnet1;  //添加委托
    stA t;
    auto key1 = evnet1 += &print;
    auto key2 = evnet1 += [&t](int a, int b){
        t.a = a;
        t.b = b;
        cout << "t.a = " << t.a << " t.b = " << t.b << endl;
    };
    auto key3 = evnet1 += std::bind(&stA::fun, &t, std::placeholders::_1, std::placeholders::_2);
  //广播
    evnet1(2, 3);
  //移除委托
    evnet1 -= key1;
    evnet1 -= key2;
    evnet1(4, 5);
  //清空事件
    evnet1.Clear();
    evnet1(1, 2);//清空什么都不会输出
}

输出结果:

(原创)c++11改进我们的模式之改进观察者模式

在第一个版本的基础上增加了+=和-=运算符,使用法更接近c#,这里+=会返回一个key,这个key用来-=删除委托时用到,这种做法不太好,只是一个简单的处理。如果内部用vector的话,-=时,根据function去删除指定的委托的话,用法就和c#完全一致了,不过,这里遇到的问题是function不支持比较操作,导致将function存入容器后,后面再根据function去删除时就找不到对应的function了。还没有足够的时间去研究这个问题,留到后面再想办法解决function比较的问题。

如果读者有更好的解决办法不妨提出来,讨论一下。

c++11 boost技术交流群:296561497,欢迎大家来交流技术。
原文链接: https://www.cnblogs.com/qicosmos/p/3145585.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/92731

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月10日 上午1:49
下一篇 2023年2月10日 上午1:50

相关推荐