How to convert from a standard factory to an object factory using boost shared pointers?

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

On 9/18/07, Stephen Torri <storri@torri.org> wrote:
This is more than enough to get started. I hope I have been clear. If not please ask me questions.
The 'components' in your factory are wrappers around default constructor, i.e. they take no arguments (this is a great way to simplify all the stuff ;-) So in this case a simple template could be enough: template<class T> static T* def_ctor_wrapper() { return new T(); } and you can instantiate it where you need without replicating all the 'Component* Create()' stuff inside each object. If you plan to support more then default c'tors, i.e if you plan to support passing arguments to your Create() functions probably you need to reconsider all the design, and complicate it a bit BTW ;-) I have sent to this mailing list a couple of weeks ago some examples of a factory that does this (and much more) in case you are interested. Original posted factory uses pure C++ with no libraries, I'm now converting it to use boost::fusion, just a way to learn myself this nice library. Marco

On Tue, 2007-09-18 at 17:07 +0200, Marco Costalba wrote:
The 'components' in your factory are wrappers around default constructor, i.e. they take no arguments (this is a great way to simplify all the stuff ;-)
So in this case a simple template could be enough:
template<class T> static T* def_ctor_wrapper() { return new T(); }
and you can instantiate it where you need without replicating all the 'Component* Create()' stuff inside each object.
If you plan to support more then default c'tors, i.e if you plan to support passing arguments to your Create() functions probably you need to reconsider all the design, and complicate it a bit BTW ;-)
I have sent to this mailing list a couple of weeks ago some examples of a factory that does this (and much more) in case you are interested.
Original posted factory uses pure C++ with no libraries, I'm now converting it to use boost::fusion, just a way to learn myself this nice library.
Marco
Can you send me the code example? Stephen
participants (2)
-
Marco Costalba
-
Stephen Torri