再谈 Object Factories(对象工厂)

为何而写:

为什么再谈一次,因为上次代码实在是不够好。上篇文章对象工厂给出的代码太过拙劣,限于学识,我自己类型擦除技术仅仅是把对象的指针转换为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和模板技术必然影响性能。具体要不要用,取决于实际需要。

时间: 2024-07-31 05:42:52

再谈 Object Factories(对象工厂)的相关文章

Object Factories(对象工厂)

1,为什么需要对象工厂? 我们创建一个对象时,必须给出具体型别,new A也好,new B也罢.A,B都是对象的型别.我们向来反对写hardcode,但却在创建对象时必须hardcode. 如果需要根据用户的输入信息,或是网络反馈信息,或是文本文件信息来创建对象时,应该怎么办呢? 最初我们想法可能是这样的,伪代码 switch(Info) { case a: return new A; case b: return new B; ... default:... } 这就是大家都熟悉简单工厂模式,

再谈包装类Integer对象的比较

public class CompareDemo { public static void main(String[] args) { int a = 128, b = 128; System.out.println(a == b); // true Integer c = 128, d = 128; System.out.println(c == d); // false System.out.println(c.equals(d)); // true Integer e = -128, f

再谈类和对象

类和对象是Java中的常见概念,类具有四个特点: 对象性,封装性,继承性,多态性. 我学到了同一个类的不同对象是独立的,也学了 this 关键字的用法,还有static 的用法,也练习了 课堂上的程序,最后还学到了构造函数,以及类的 运行图. 也学到了作用域的概念,内部的作用域可以访问外部 的作用域,外部的不能访问内部的同名变量,今天 课堂上的例子代码量加大了一些,很多东西要好好 吸收和多看几次! 原文地址:https://www.cnblogs.com/sjnnjs/p/10742523.ht

Another Look at Events(再谈Events)

转载:http://www.qtcn.org/bbs/simple/?t31383.html Another Look at Events(再谈Events) 最近在学习Qt事件处理的时候发现一篇很不错的文章,是2004年季刊的一篇文章,网上有这篇文章的翻译版,但是感觉部分地方翻译的比较粗糙,不是很明确.索性重新翻译了一遍,并引用了原翻译版的一段译注.以下都是用自己能理解的方式来翻译的,由于水平有限,有很多不足的地方,希望大家指正. Another Look at Events (再谈Event

Javascript我学之六对象工厂函数与构造函数

本文是金旭亮老师网易云课堂的课程笔记,记录下来,以供备忘. 概述 使用对象字面量,或者向空对象中动态地添加新成员,是最简单易用的对象创建方法. 然而,除了这两种常用的对象创建方式,JavaScript还提供了其他方法创建对象. 1).使用工厂函数创建对象 我们可以编写一个函数,此函数的功能就是创建对象,可将其称为“对象工厂方法”. 1 //工厂函数 2 function createPerson(name, age, job) { 3 var o = new Object(); 4 o.name

OpenglES2.0 for Android:再谈纹理映射

OpenglES2.0 for Android:再谈纹理映射 前言 上一节我们实现了一个简单的纹理映射的例子--一个简单的贴图,这节我们来做一些稍微复杂一点的例子,最后再给我们前面的立方体做一个纹理. 纹理拉伸 重复拉伸方式 这种是经常使用的一张纹理拉伸方式,常用于绘制一些重复的元素,比如我们在游戏绘制一幅方格式的地图时.使用重复拉伸方式使得纹理能够根据目标平 面的大小自动重复,这样既不会失去纹理图的效果,也可以节省内存.如下图所示: 实现起来很简单,我们回到上节的项目,找到我们纹理的工具类Te

再谈word2003编程

再谈word2003编程 近期因为项目需要,写了许多word2003编程的东东.有时候遇到难题想查sdk说明,很难找到中文解释,对于e文不好的我来说,简直是天书.想必很多人多有感慨.     下面列出内容是一些常用的内容说明,希望对大家有帮助.     那就开始吧注意,下文的WAPP是我定义的word文档工程变量 的 //合并单元格    table.Cell(2, 2).Merge(table.Cell(2, 3));  //单元格分离     object Rownum = 2;     o

Unity教程之再谈Unity中的优化技术

这是从 Unity教程之再谈Unity中的优化技术 这篇文章里提取出来的一部分,这篇文章让我学到了挺多可能我应该知道却还没知道的知识,写的挺好的 优化几何体 这一步主要是为了针对性能瓶颈中的”顶点处理“一项.这里的几何体就是指组成场景中对象的网格结构. 3D游戏制作都由模型制作开始.而在建模时,有一条我们需要记住:尽可能减少模型中三角形的数目,一些对于模型没有影响.或是肉眼非常难察觉到区别的顶点都要尽可能去掉.例如在下面左图中,正方体内部很多顶点都是不需要的,而把这个模型导入到Unity里就会是

再谈JSON -json定义及数据类型

再谈json 最近在项目中使用到了highcharts ,highstock做了一些统计分析,使用jQuery ajax那就不得不使用json, 但是在使用过程中也出现了很多的疑惑,比如说,什么情况下我们需要去将字符串转换为json对象,什么情况下就不需要转换.通过hql和sql查询返回的list,通过json array 写入response,接下来json就上场了. 在这里就复制粘贴,再对其的基本定义进行一些区分. json:(JavaScript Object Notation) 是一种轻