Boost logo

Boost :

From: Stephen Torri (storri_at_[hidden])
Date: 2007-09-18 10:39:29


PROBLEM: How to use Boost shared_ptr for returning the new Component
object from an object factory?

DESCRIPTION:

I have a class which is acting as a factory for all the components in a
system. The problem is that this class is getting large and I am
concerned about its future growth. My idea is to switch to using an
object factory which has a map of registered components. The creation
code for each component will be inside the class rather than in this
factory class.

        #ifndef COMPONENT_FACTORY_H_
        #define COMPONENT_FACTORY_H_
        
        #include <boost/shared_ptr.hpp>
        #include "libreverse/infrastructure/Component_Types.h"
        
        namespace produce { namespace infrastructure {
        
            class Component_Factory {
            public:
        
                static Component_Factory& Instance();
        
                infrastructure_types::Component::ptr_t get_Apple ( boost::uint32_t id );
        
                infrastructure_types::Component::ptr_t get_Berry ( boost::uint32_t id );
        
                infrastructure_types::Component::ptr_t get_Carrot ( boost::uint32_t id );
        
            private:
        
                Component_Factory (){}
                Component_Factory ( const Component_Factory& );
                Component_Factory& operator = ( const Component_Factory& );
                ~Component_Factory (){}
            };
        
        } /* namespace infrastructure */
        } /* namespace produce */
        
        #endif /* COMPONENT_FACTORY_H_ */
        
If I keep this up I will have a ton of functions for creating each type
of fruit or vegatable. So I would rather not have this. So I went for an
object factory that I saw in Alexandrescu's Modern C++ Design:

        #include <map>
        #include <iostream>
        #include <boost/shared_ptr.hpp>
        #include <boost/bind.hpp>
        #include <boost/function.hpp>
        
        namespace tool
        {
          namespace component
          {
            class Component
            {};
        
            class Apple : public Component
            {
            public:
        
              static const int ID = 1;
        
              static Component* Create()
              {
                return new Apple;
              }
        
            };
        
            class Blueberry : public Component
            {
            public:
        
              static const int ID = 5;
        
              static Component* Create()
              {
                return new Blueberry;
              }
            };
          }
        
          namespace infrastructure
          {
        
            class Component_Factory
            {
            public:
              typedef component::Component* (*CreateComponentCallback)();
        
              static Component_Factory& Instance()
              {
                static Component_Factory obj;
                return obj;
              }
              
              bool RegisterComponent ( int component_id,
                                       CreateComponentCallback call_func )
              {
                return m_callbacks.insert ( CallbackMap::value_type ( component_id, call_func ) ).second;
              }
              
              bool UnregisterComponent ( int component_id )
              {
                return m_callbacks.erase ( component_id ) == 1;
              }
        
              component::Component* CreateComponent ( int component_id )
              {
                CallbackMap::const_iterator pos = m_callbacks.find ( component_id );
        
                if ( pos == m_callbacks.end() )
                  {
                    std::cerr << "Unknown Component ID" << std::endl;
                    abort();
                  }
        
                return (pos->second)();
              }
              
            private:
              typedef std::map<int, CreateComponentCallback> CallbackMap;
              
              CallbackMap m_callbacks;
        
              Component_Factory()
              {
                this->RegisterComponent ( tool::component::Apple::ID, &tool::component::Apple::Create );
                this->RegisterComponent ( tool::component::Blueberry::ID, &tool::component::Blueberry::Create );
              }
        
              Component_Factory ( Component_Factory const& rhs );
              Component_Factory& operator= ( Component_Factory const& rhs );
              ~Component_Factory(){}
            };
        
          }
        }

In this example the many factory functions to create a type are replaced
by one function. The code to create the object is placed in a function
in the object's class. That way the object is responsible for creating a
copy of itself.

The problem is that I am not sure how to use the boost shared pointer
here. I have no problem changing the Component* places to have a
boost::shared_ptr<Component>. Its the callback function signature that
has me stumped.

      typedef component::Component* (*CreateComponentCallback)();

Do I simply do:

      typedef boost::shared_ptr<component::Component> (*CreateComponentCallback)();

What about the callback function? Can I replace that with the operator()
in each of the classes so that I can replace the static Create function?
I would like to make a purely virtual function in the Component class
that requires the child class to have the operator() function for
creating a new instance of the child class.

This is more than enough to get started. I hope I have been clear. If
not please ask me questions.

Stephen


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk