1. 程式人生 > >C++ 11標準簡單實現觀察者模式

C++ 11標準簡單實現觀察者模式

觀察者模式簡單理解:被觀察者的狀態發生變化,觀察者的行為同時也發生變化。

觀察者模式的簡單應用:

          1.宣告被觀察者物件。

          2.觀察者向被觀察者註冊訊息相應函式。

          3.觀察者屬性發生變化,同時註冊上的觀察者出發響應。

上面就是我對觀察者的簡單的理解,但是實際上並不只是如此。 目前有很多開源庫都實現了這樣的模式。譬如Qt中的connect函式,boost庫中的signals2模組等等。有興趣的朋友可以看看他們的原始碼。我這裡只是一個簡單的實現,沒有非常強大的功能。

以下是我寫的程式碼, 在vs2017上面是驗證沒有問題的。

#ifndef __DELEGATE_H__
#define __DELEGATE_H__
#include <iostream>
#include <list>
#include <functional>
#include <algorithm>

template <typename>
class delegate{};

template <typename R,typename ...Args>
class delegate<R(Args...)>{
    typedef std::function<R(Args...)> delegate_func;
    typedef std::list<delegate_func> func_list;

    public:
        delegate();
        delegate(const unsigned int& count);
        ~delegate();

        bool empty() const;
        bool full() const;
        unsigned int size() const;
        void resize(const int& size);
        unsigned int max_size() const;


        bool connect( delegate_func& func);
        template<typename C>
        bool connect(R(C::*func)(Args...),C* c_ptr);
        template<typename C>
        bool connect(C& mem);

        bool disconnect(delegate_func func);
        template<typename C>
        bool disconnect(R(C::*func)(Args...),C* c_ptr);
        template<typename C>
        bool disconnect(C& mem);

        bool disconnect_all();

        void emit(Args&& ...args) const;


    private:
        func_list _list;
        unsigned int _max_count;
};

template <typename R,typename ...Args>
    delegate<R(Args...)>::delegate()
        :_max_count(0)
    {
        
    }

template <typename R,typename ...Args>
    delegate<R(Args...)>::delegate(const unsigned int& count)
        :_max_count(count)
    {
    }

template <typename R,typename ...Args>
    delegate<R(Args...)>::~delegate()
    {
        _max_count = 0;
        _list.clear();
    }

template<typename R,typename ...Args>
    bool delegate<R(Args...)>::empty() const
    {
        return _list.empty();
    }


template<typename R,typename ...Args>
    unsigned int delegate<R(Args...)>::size() const
    {
        return _list.size();
    }

template<typename R,typename ...Args>
    bool delegate<R(Args...)>::full() const
    {
        return size() >= max_size() ? true : false;
    }

template<typename R,typename ...Args>
    void delegate<R(Args...)>::resize(const int& size)
    {
        this._max_count = size;
    }

template<typename R,typename ...Args>
    unsigned int delegate<R(Args...)>::max_size() const
    {
        return _max_count;
    }

template <typename R,typename ...Args>
    bool delegate<R(Args...)>::connect(delegate_func& func)
    {
        bool ret = false;
        if(!full)
        {
            _list.push_back(func);
            ret = true;
        }
        return ret;
    }

template <typename R,typename ...Args>
    template<typename C>
        bool delegate<R(Args...)>::connect(R(C::*func)(Args...), C* c_ptr)
        {
            bool ret = false;
            if(!full())
            {
                _list.push_back(std::bind(func,c_ptr,std::placeholders::_1));
                ret = true;
            }
            return ret;
        }

template <typename R,typename ...Args>
    template<typename C>
            bool delegate<R(Args...)>::connect(C& mem)
            {
                bool ret = false;
                delegate_func func = mem;
                if(!full())
                {
                    _list.push_back(func);
                    ret = true;
                }
                return ret;
            }


template <typename R,typename ...Args>
    bool delegate<R(Args...)>::disconnect(delegate_func func)
    {
        bool ret = false;
        auto itor = std::find_if(_list.begin(), _list.end(),
            [&](delegate_func& f) -> bool
        {
            delegate_func &fn = func;
            if (f && f.target<R(*)(Args...)>() == fn.target<R(*)(Args...)>())
            {
                return true;
            }
            return false;
        });
        if (itor != _list.end())
        {
            _list.erase(itor);
            ret = true;
        }
        return ret;
    }

template <typename R,typename ...Args>
    template<typename C>
        bool delegate<R(Args...)>::disconnect(R(C::*func)(Args...),C* c_ptr)
        {
            bool ret = false;
            auto itor = std::find_if(_list.begin(),_list.end(),[&](delegate_func& f)->bool{
                delegate_func fc = std::bind(func,c_ptr);

                if(f && f.target<R(*)(Args...)>() == fc.target<R(*)(Args...)>())
                {
                    return true;
                }
                return false;
            });
            if(itor != _list.end())
            {
                _list.erase(itor);
                ret = true;
            }
            return ret;
        }

template <typename R,typename ...Args>
    template<typename C>
            bool delegate<R(Args...)>::disconnect(C& mem)
            {
                bool ret = false;
                auto itor = std::find_if(_list.begin(), _list.end(),
                    [&](delegate_func& f) -> bool
                {
                    delegate_func &fn = mem;
                    if (f && f.target<R(*)(Args...)>() == fn.target<R(*)(Args...)>())
                    {
                        return true;
                    }
                    return false;
                });
                if (itor != _list.end())
                {
                    _list.erase(itor);
                    ret = true;
                }
                return ret;
            }

template<typename R,typename ...Args>
    bool delegate<R(Args...)>::disconnect_all()
    {
            bool ret = false;
            _list.clear();
            if(empty())
            {
                ret = true;
            }
            return ret;
    }

template<typename R,typename ...Args>
    void delegate<R(Args...)>::emit(Args&& ...args) const
    {
        for(auto func : _list)
        {
            try{
                func(args...);
            }
            catch(std::exception& ex)
            {
                std::cout << ex.what() << std::endl;
            }
        }
    }

#endif //__DELEGATE_H__

注意:在我寫這段程式碼的時候,由於沒有考慮的特別清楚,使用了std::list容器當作了觀察者函式的載體。所以,在disconnect的時候我是使用std::function中的target來判斷兩個std::function物件是否相等。但是,從網上查了下資料。這樣的判斷並不完美,會存在錯誤。  所以,如果有想使用這塊程式碼的同學們,可以使用std::unordered_map 容器來替代list容器。這裡可能會有同學問我為什麼不使用map容器,哈哈。雖然扯的有點遠,但是我想說的是map容器會實現自動排序。這個功能我們並不需要。為了節約那麼一丟丟的效能。(其實這裡我想說的是寫程式碼的時候要選擇合適的)。

最後,我就不貼測試程式碼了, 有興趣的可以自己寫一寫。