Skip to content
Snippets Groups Projects

Resolve "Factory documentation"

Merged Joan Solà Ortega requested to merge 299-factory-documentation into devel
Files
4
@@ -25,42 +25,68 @@ namespace wolf
@@ -25,42 +25,68 @@ namespace wolf
/** \brief Singleton template factory
/** \brief Singleton template factory
*
*
* This class implements a generic factory as a singleton.
* This template class implements a generic factory as a singleton.
*
* > IMPORTANT: This template factory can be used to construct many different objects except:
* > - Objects deriving from SensorBase --> see FactorySensor
* > - Objects deriving from ProcessorBase --> see FactoryProcessor
* >
* > The reason for this is that the two cases above need a more elaborated API than the one in this template class.
*
*
* \param TypeBase base type of all the objects created by the factory
* \param TypeBase base type of all the objects created by the factory
* \param TypeInput type of the input argument. Typical cases are std::string for file names, and YAML::Node for YAML nodes.
* \param TypeInput variadic type for the input arguments.
 
*
 
* ### Template specialization
*
*
* - The class is templatized on the class of the produced objects, __TypeBase__.
* - The class is templatized on the class of the produced objects, __TypeBase__.
* The produced objects are always of a class deriving from TypeBase.
* The produced objects are always of a class deriving from TypeBase.
* The returned data is always a pointer to TypeBase.
* The returned data is always a shared pointer to TypeBase.
*
*
* For example, you may use as __TypeBase__ the following types:
* For example, you may use as __TypeBase__ the following types:
* - LandmarkBase: the Factory creates landmarks deriving from LandmarkBase and returns base pointers ````LandmarkBasePtr```` to them
* - LandmarkBase: the Factory creates landmarks deriving from LandmarkBase and returns base pointers ````LandmarkBasePtr```` to them
* - ParamsSensorBase: the Factory creates intrinsic parameters deriving from ParamsSensorBase and returns base pointers ````ParamsSensorBasePtr```` to them
* - ParamsSensorBase: the Factory creates intrinsic parameters deriving from ParamsSensorBase and returns base pointers ````ParamsSensorBasePtr```` to them
* - XxxBase: the Factory creates objects deriving from XxxBase and returns pointers ````XxxBasePtr```` to them.
* - XxxBase: the Factory creates objects deriving from XxxBase and returns pointers ````XxxBasePtr```` to them.
*
*
* - The class in also templatized on the type of the input parameter of the creator, __TypeInput__:
* - The class is variadic-templatized on the types of the input parameter of the creator, __TypeInput__:
* - ````std::string```` is used when the input parameter is a file name from which to read data (typically a YAML file).
* - ````std::string```` is used when the input parameter is a file name from which to read data (typically a YAML file).
* - ````YAML::Node```` is used when the input parameter is a YAML node with structured data.
* - ````std::string, wolf::ParamsServer``` is used when nodes are build from parameters in the ParamsServer
 
* - ````YAML::Node```` is used when the input parameter is a YAML node with structured data.
 
* - Any other variadic list of inputs is possible.
 
*
 
* - Examples of specific factories existing in Wolf are:
 
* \code
 
*
 
* // FactorySensor
 
* typedef Factory<SensorBase, // Type of objects to be returned: SensorBasePtr
 
* const std::string&, // Type of the sensor: name of the derived sensor class
 
* const Eigen::VectorXd&, // Sensor extrinsics
 
* const ParamsSensorBasePtr> // Sensor parameters
 
* FactorySensor;
 
*
 
* // FactoryProcessor
 
* typedef Factory<ProcessorBase, // Type of object returned: ProcessorBasePtr
 
* const std::string&, // Type of the processor: name of the derived processor class
 
* const ParamsProcessorBasePtr> // Parameters for creating the processor
 
* FactoryProcessor;
 
*
 
* // AutoConfProcessorFactory
 
* typedef Factory<ProcessorBase, // Type of object returned: ProcessorBasePtr
 
* const std::string&, // Type of the processor: name of the derived processor class
 
* const ParamsServer> // Parameters for creating the processor
 
* AutoConfProcessorFactory;
 
*
 
* // Landmarks from YAML
 
* typedef Factory<LandmarkBase, // Type of node created: LandmarkBasePtr
 
* const YAML::Node&> // YAML node with the lmk params
 
* LandmarkFactory;
 
* \endcode
*
*
* ### Operation of the factory
* ### Operation of the factory
*
*
* #### Rationale
* #### Rationale
*
*
* This factory can create objects of classes deriving from TypeBase.
* Once specialized, this factory can create objects of classes deriving from TypeBase.
*
*
* > For example, if you want to make a Landmark factory, set TypeBase = LandmarkBase.\n
* > For example, if you want to make a Landmark factory, set TypeBase = LandmarkBase.\n
* > Then, the factory will create specific landmarks deriving from LandmarkBase.\n
* > Then, the factory will create specific landmarks deriving from LandmarkBase.\n
* > The specific type of landmark (e.g. LandmarkCorner2d, LandmarkAHP, LandmarkPolyline2d, etc) is indicated by a string that we call TYPE in this documentation.
* > The specific type of landmark (e.g. LandmarkCorner2d, LandmarkAHP, LandmarkPolyline2d, etc) is indicated by a string that we call TYPE in this documentation.
*
*
* Specific object creation is invoked by the method ````create(TYPE, params ... )````, where
* Specific object creation is invoked by the method ````create(TYPE, params ... )````, where
* - the TYPE of object to create is identified with a string
* - the TYPE of object to create is identified with a string. This string matches the name of the derived class.
* - the params may be provided in different forms -- see TypeInput.
* - the params may be provided in different forms -- see TypeInput.
*
*
* The methods to create specific objects are called __creators__.
* The methods to create specific objects are called __creators__.
@@ -75,23 +101,31 @@ namespace wolf
@@ -75,23 +101,31 @@ namespace wolf
* - Examples: Write and register a landmark creator for LandmarkPolyline2d.
* - Examples: Write and register a landmark creator for LandmarkPolyline2d.
*
*
* #### Define correct TYPE names
* #### Define correct TYPE names
* The rule to make new TYPE strings unique is that you skip the generic 'Type' prefix from your class name,
* We use a std::string with literally the same text as the derived class name, e.g.:
* and you build a string in CAPITALS with space separators, e.g.:
* - ParamsSensorCamera -> ````"ParamsSensorCamera"````
* - ParamsSensorCamera -> ````"CAMERA"````
* - SensorCamera -> ````"SensorCamera"````
* - ParamsSensorLaser2d -> ````"LASER 2d"````
* - ParamsSensorLaser2d -> ````"ParamsSensorLaser2d"````
* - LandmarkPolyline2d -> ````"POLYLINE 2d"````
* - SensorLaser2d -> ````"SensorLaser2d"````
 
* - LandmarkPolyline2d -> ````"LandmarkPolyline2d"````
* - etc.
* - etc.
*
*
* #### Access the factory
* #### Access the factory
 
*
* The first thing to know is that we have defined typedefs for the templates that we are using. For example:
* The first thing to know is that we have defined typedefs for the templates that we are using. For example:
*
*
* \code
* \code
* typedef Factory<ParamsSensorBase, std::string> FactoryParamsSensor;
* typedef Factory<ParamsSensorBase, std::string> FactoryParamsSensor;
* typedef Factory<ParamsProcessorBase, std::string> FactoryParamsProcessor;
* typedef Factory<ParamsProcessorBase, std::string> FactoryParamsProcessor;
* typedef Factory<LandmarkBase, YAML::Node> FactoryLandmark;
* typedef Factory<LandmarkBase, YAML::Node> FactoryLandmark;
 
* typedef Factory<SensorBase,
 
* const std::string&,
 
* const Eigen::VectorXd&,
 
* const ParamsSensorBasePtr> FactorySensor;
 
*
* \endcode
* \endcode
*
*
* Second to know, the Factory class is a <a href="http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289">singleton</a>: it can only exist once in your application.
* Second to know, the Factory class is a <a href="http://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289">singleton</a>:
 
* it can only exist once in your application.
* To access it, use the static method get(),
* To access it, use the static method get(),
*
*
* \code
* \code
@@ -103,10 +137,11 @@ namespace wolf
@@ -103,10 +137,11 @@ namespace wolf
* You can then call the methods you like, e.g. to create a landmark, you use:
* You can then call the methods you like, e.g. to create a landmark, you use:
*
*
* \code
* \code
* FactoryLandmark::get().create(...); // see below for creating objects ...
* FactoryLandmark::get().create(TYPE, args...); // see below for creating objects ...
* \endcode
* \endcode
*
*
* #### Write creator methods (in your derived object classes)
* #### Write creator methods (in your derived object classes)
 
*
* The method LandmarkPolyline2d::create(...) exists in the LandmarkPolyline2d class as a static method.
* The method LandmarkPolyline2d::create(...) exists in the LandmarkPolyline2d class as a static method.
* All these ````XxxXxx::create()```` methods need to have exactly the same API, regardless of the object type.
* All these ````XxxXxx::create()```` methods need to have exactly the same API, regardless of the object type.
* The API puts into play the two template parameters:
* The API puts into play the two template parameters:
@@ -117,13 +152,13 @@ namespace wolf
@@ -117,13 +152,13 @@ namespace wolf
*
*
* This API includes an element of type TypeInput, which might be either a std::string, or a YAML::node:
* This API includes an element of type TypeInput, which might be either a std::string, or a YAML::node:
* - ````std::string```` is used to indicate the name of a configuration file. These files are usually YAML files containing configuration data to create your object.
* - ````std::string```` is used to indicate the name of a configuration file. These files are usually YAML files containing configuration data to create your object.
* - ````YAML::Node```` is used to access parts of a YAML file already encoded as nodes, such as when loading landmarks from a SLAM map stored as a YAML file.
* - ````YAML::Node```` is used to access parts of a YAML file already encoded as nodes, such as when loading landmarks from a SLAM map stored as a YAML file.
*
*
* Two examples:
* Two examples:
*
*
* \code
* \code
* static ParamsSensorBasePtr create(const std::string& _intrinsics_dot_yaml)
* static ParamsSensorBasePtr create(const std::string& _intrinsics_dot_yaml)
* static LandmarkBasePtr create(const YAML::Node& _lmk_yaml_node)
* static LandmarkBasePtr create(const YAML::Node& _lmk_yaml_node)
* \endcode
* \endcode
*
*
* See further down for an implementation example.
* See further down for an implementation example.
@@ -137,7 +172,7 @@ namespace wolf
@@ -137,7 +172,7 @@ namespace wolf
* that knows how to create your specific object, e.g.:
* that knows how to create your specific object, e.g.:
*
*
* \code
* \code
* FactoryLandmark::get().registerCreator("POLYLINE 2d", LandmarkPolyline2d::create);
* FactoryLandmark::get().registerCreator("LandmarkPolyline2d", LandmarkPolyline2d::create);
* \endcode
* \endcode
*
*
* #### Automatic registration
* #### Automatic registration
@@ -145,7 +180,7 @@ namespace wolf
@@ -145,7 +180,7 @@ namespace wolf
* For example, in sensor_camera_yaml.cpp we find the line:
* For example, in sensor_camera_yaml.cpp we find the line:
*
*
* \code
* \code
* const bool registered_camera_intr = FactoryParamsSensor::get().registerCreator("CAMERA", createParamsSensorCamera);
* const bool registered_camera_intr = FactoryParamsSensor::get().registerCreator("ParamsSensorCamera", createParamsSensorCamera);
* \endcode
* \endcode
*
*
* which is a static invocation (i.e., it is placed at global scope outside of the ParamsSensorCamera class).
* which is a static invocation (i.e., it is placed at global scope outside of the ParamsSensorCamera class).
@@ -156,7 +191,7 @@ namespace wolf
@@ -156,7 +191,7 @@ namespace wolf
* The method unregisterCreator() unregisters the ObjectXxx::create() method. It only needs to be passed the string of the object type.
* The method unregisterCreator() unregisters the ObjectXxx::create() method. It only needs to be passed the string of the object type.
*
*
* \code
* \code
* Factory<MyTypeBase, MyTypeInput>::get().unregisterCreator("CAMERA");
* Factory<MyTypeBase, MyTypeInput>::get().unregisterCreator("ParamsSensorCamera");
* \endcode
* \endcode
*
*
* #### Create objects using the factory
* #### Create objects using the factory
@@ -166,13 +201,13 @@ namespace wolf
@@ -166,13 +201,13 @@ namespace wolf
* To create e.g. a LandmarkPolyline2d from a YAML node you type:
* To create e.g. a LandmarkPolyline2d from a YAML node you type:
*
*
* \code
* \code
* LandmarkBasePtr lmk_ptr = Factory<LandmarkBasePtr, YAML::Node>::get().create("POLYLINE 2d", lmk_yaml_node);
* LandmarkBasePtr lmk_ptr = Factory<LandmarkBasePtr, YAML::Node>::get().create("LandmarkPolyline2d", lmk_yaml_node);
* \endcode
* \endcode
*
*
* or even better, make use of the convenient typedefs:
* or even better, make use of the convenient typedefs:
*
*
* \code
* \code
* LandmarkBasePtr lmk_ptr = FactoryLandmark::get().create("POLYLINE 2d", lmk_yaml_node);
* LandmarkBasePtr lmk_ptr = FactoryLandmark::get().create("LandmarkPolyline2d", lmk_yaml_node);
* \endcode
* \endcode
*
*
* ### Examples
* ### Examples
@@ -197,7 +232,7 @@ namespace wolf
@@ -197,7 +232,7 @@ namespace wolf
* }
* }
*
*
* // Create a new landmark
* // Create a new landmark
* LandmarkBasePtr lmk_ptr = new LandmarkPolyline2d(points, first_defined, last_defined, first_id);
* LandmarkBasePtr lmk_ptr = std::make_shared<LandmarkPolyline2d>(points, first_defined, last_defined, first_id);
* lmk_ptr->setId(id);
* lmk_ptr->setId(id);
*
*
* return lmk_ptr;
* return lmk_ptr;
@@ -212,7 +247,7 @@ namespace wolf
@@ -212,7 +247,7 @@ namespace wolf
* // Register landmark creator (put the register code inside an unnamed namespace):
* // Register landmark creator (put the register code inside an unnamed namespace):
* namespace
* namespace
* {
* {
* const bool registered_lmk_polyline_2d = FactoryLandmark::get().registerCreator("POLYLINE 2d", LandmarkPolyline2d::create);
* const bool registered_lmk_polyline_2d = FactoryLandmark::get().registerCreator("LandmarkPolyline2d", LandmarkPolyline2d::create);
* }
* }
*
*
* \endcode
* \endcode
@@ -234,12 +269,16 @@ namespace wolf
@@ -234,12 +269,16 @@ namespace wolf
template<class TypeBase, typename... TypeInput>
template<class TypeBase, typename... TypeInput>
class Factory
class Factory
{
{
 
private:
typedef std::shared_ptr<TypeBase> TypeBasePtr;
typedef std::shared_ptr<TypeBase> TypeBasePtr;
 
public:
public:
// example of creator callback (see typedefs below)
// example of creator callback (see typedefs below)
typedef TypeBasePtr (*CreatorCallback)(TypeInput... _input);
typedef TypeBasePtr (*CreatorCallback)(TypeInput... _input);
 
private:
private:
typedef std::map<std::string, CreatorCallback> CallbackMap;
typedef std::map<std::string, CreatorCallback> CallbackMap;
 
public:
public:
bool registerCreator(const std::string& _type, CreatorCallback createFn);
bool registerCreator(const std::string& _type, CreatorCallback createFn);
bool unregisterCreator(const std::string& _type);
bool unregisterCreator(const std::string& _type);
Loading