zoukankan      html  css  js  c++  java
  • (原创)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<typename F>
    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#,这里+=会返回一个key,这个key用来-=删除委托时用到,这种做法不太好,只是一个简单的处理。如果内部用vector的话,-=时,根据function去删除指定的委托的话,用法就和c#完全一致了,不过,这里遇到的问题是function不支持比较操作,导致将function存入容器后,后面再根据function去删除时就找不到对应的function了。还没有足够的时间去研究这个问题,留到后面再想办法解决function比较的问题。

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

    c++11 boost技术交流群:296561497,欢迎大家来交流技术。

  • 相关阅读:
    Jquery EasyUI tabs处理
    C# ToString格式控制符
    SQL删除重复数据,保留一条
    stm32f4xx 的IWDG使用的一般步骤
    stm32f4xx 的EXTI使用的一般步骤
    STM32F4xx---EXTI 外部中断
    数组和指针 到 存储类(1)
    uCosII 从 OSStart开始到思维定势··········
    《C和指针》一书介绍操作符优先级
    OSTimeTick()函数解析
  • 原文地址:https://www.cnblogs.com/qicosmos/p/3145585.html
Copyright © 2011-2022 走看看