程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 再談 Object Factories(對象工廠),objectfactories

再談 Object Factories(對象工廠),objectfactories

編輯:C++入門知識

再談 Object Factories(對象工廠),objectfactories


為何而寫:

為什麼再談一次,因為上次代碼實在是不夠好。上篇文章 對象工廠給出的代碼太過拙劣,限於學識,我自己類型擦除技術僅僅是把對象的指針轉換為void* 而已,實際上可以更為巧妙。這次利用新的類型擦出技術,給出一個完美的解決方,請看下文。

前情描述:

我 為什麼不直接保存用戶提供的function的void*而非要把他copy一份利用容器vector儲存起來,然後再去取其指針轉換為void*。是因 為用戶傳來的function可能是右值或臨時值,一個馬上要被刪除的值,如果我們直接使用用戶提供的function的void*,該指針很可能是懸垂 指針。

  • 首先,存儲函數遇到了麻煩。因為一個容器只能存儲相同類型的元素,所以我其實創建了許多不同類型的靜態vector來存儲不同類型的function。將vector轉換為void*,把vector的void* ,索引值,鍵值一並將其加入map中。
  • 其次,我在注銷工廠函數時遇到了更大的麻煩(必須強迫用戶出類型標示),因為我們已經失去了存在function容器的類型,同樣失去了function具體類型,沒有類型信息我無法刪除容器中的元素。

就算以上兩個問題都不是是問題,這樣的代碼實現方式真是拙劣。我自己都無法直視。

真正需求:

所以,我們需要一個能儲存任何元素的容器,該容器類型唯一,這樣我們解決了以上兩個麻煩。

其一,我們不在需要創建多個容器,因為這個類型的容器可以儲存任何類型的元素。

其二,我們的注銷方法不在需要強迫用戶給出具體的類型信息,因為容器知道如何刪除元素,原因在於容器類型保留下來。

 

一個能儲存任何元素類型的容器,在Java中也許是這樣ArrayList<Object>,因為所有類均繼承子Object。恩,在C++中如何實現,C++中缺少這樣一個父類!

Boost:

早聞boost大名,但一直以為stl都沒有完全搞懂,所以不想去研究boost,但boost真的能為我們提供一個可以儲存任何類型的容器。他就是boost::any,我這裡深入介紹boost::any,把源碼貼出來分享給大家。

class any
    {
    public: // structors

        any() BOOST_NOEXCEPT
          : content(0)
        {
        }

        template<typename ValueType>
        any(const ValueType & value)
          : content(new holder<
                BOOST_DEDUCED_TYPENAME remove_cv<BOOST_DEDUCED_TYPENAME decay<const ValueType>::type>::type
            >(value))
        {
        }

        any(const any & other)
          : content(other.content ? other.content->clone() : 0)
        {
        }

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
        // Move constructor
        any(any&& other) BOOST_NOEXCEPT
          : content(other.content)
        {
            other.content = 0;
        }

        // Perfect forwarding of ValueType
        template<typename ValueType>
        any(ValueType&& value
            , typename boost::disable_if<boost::is_same<any&, ValueType> >::type* = 0 // disable if value has type `any&`
            , typename boost::disable_if<boost::is_const<ValueType> >::type* = 0) // disable if value has type `const ValueType&&`
          : content(new holder< typename decay<ValueType>::type >(static_cast<ValueType&&>(value)))
        {
        }
#endif

        ~any() BOOST_NOEXCEPT
        {
            delete content;
        }

    public: // modifiers

        any & swap(any & rhs) BOOST_NOEXCEPT
        {
            std::swap(content, rhs.content);
            return *this;
        }


#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
        template<typename ValueType>
        any & operator=(const ValueType & rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

        any & operator=(any rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

#else 
        any & operator=(const any& rhs)
        {
            any(rhs).swap(*this);
            return *this;
        }

        // move assignement
        any & operator=(any&& rhs) BOOST_NOEXCEPT
        {
            rhs.swap(*this);
            any().swap(rhs);
            return *this;
        }

        // Perfect forwarding of ValueType
        template <class ValueType>
        any & operator=(ValueType&& rhs)
        {
            any(static_cast<ValueType&&>(rhs)).swap(*this);
            return *this;
        }
#endif

    public: // queries

        bool empty() const BOOST_NOEXCEPT
        {
            return !content;
        }

        void clear() BOOST_NOEXCEPT
        {
            any().swap(*this);
        }

        const boost::typeindex::type_info& type() const BOOST_NOEXCEPT
        {
            return content ? content->type() : boost::typeindex::type_id<void>().type_info();
        }

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
    private: // types
#else
    public: // types (public so any_cast can be non-friend)
#endif

        class placeholder
        {
        public: // structors

            virtual ~placeholder()
            {
            }

        public: // queries

            virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0;

            virtual placeholder * clone() const = 0;

        };

        template<typename ValueType>
        class holder : public placeholder
        {
        public: // structors

            holder(const ValueType & value)
              : held(value)
            {
            }

#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
            holder(ValueType&& value)
              : held(static_cast< ValueType&& >(value))
            {
            }
#endif
        public: // queries

            virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT
            {
                return boost::typeindex::type_id<ValueType>().type_info();
            }

            virtual placeholder * clone() const
            {
                return new holder(held);
            }

        public: // representation

            ValueType held;

        private: // intentionally left unimplemented
            holder & operator=(const holder &);
        };

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS

    private: // representation

        template<typename ValueType>
        friend ValueType * any_cast(any *) BOOST_NOEXCEPT;

        template<typename ValueType>
        friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT;

#else

    public: // representation (public so any_cast can be non-friend)

#endif

        placeholder * content;

    };

 

在上述代碼中,關鍵是要理解placeholder和holder,實際上 placeholder充當了Java中Object,作為萬物的父類。holder是我們的類的一個包裝,聚合我們的類對象。而any類持有一個執行包 裝類的父類指針。另外,在any類的實現這裡用到了虛復制構造函數技術。

重頭戲,對象工廠:

來吧,先把代碼貼上來,talking is cheap,show you the code.

template <typename AbstractProduct ,typename IdentifierType = string> class Factory
{
public:
    template <typename... Arg> bool Register(const IdentifierType& id,const function<unique_ptr<AbstractProduct>(Arg...)>& creator)
    {
        typename AssocMap::const_iterator i =associations_.find(id);
        if(i!= associations_.end()) return false;
        return associations_.insert(typename AssocMap::value_type(id,creator)).second;

    }
     bool UnRegister(const IdentifierType& id)
    {
        typename AssocMap::const_iterator i =associations_.find(id);

        return associations_.erase(id)==1;
    }


    template <typename... Arg> unique_ptr<AbstractProduct> Createobject(const IdentifierType& id,Arg&&... args)
    {
        typename AssocMap::const_iterator i =associations_.find(id);

        if(i != associations_.end())
        {
            auto funp=boost::any_cast<std::function<unique_ptr<AbstractProduct>(Arg...)> >(&(i->second));//i->second類型是boost::any
            assert(funp);//如果無法轉換,funp將是空指針
            return (*funp)(std::forward<Arg>(args)...);//完美轉發
        }
        assert(false);

    }


private:
typedef std::unordered_map<IdentifierType,boost::any> AssocMap;//存儲任意類型的map
AssocMap associations_;
};

 

代碼瞬間簡單了很多,我再關鍵位置加入了注釋,上述代碼使用 變長參數模板技術,完美轉發,智能指針,unordered_map,所以要想通過編譯,必須啟用C++11。據我所知,不成形的C++17標准已經出來了,所以盡快熟悉新標准吧。當然還需要boost庫支持。

你需要靈活性,則需要花費性能,靈活性不是沒有代價的,我們的靈活性在於我的工廠支持注冊任意形式調用形式,只要求函數的返回值,但我們使用RTTI和模板技術必然影響性能。具體要不要用,取決於實際需要。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved