|
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