CFEL - ASG Software Suite  2.5.0
CASS
generic_factory.hpp
Go to the documentation of this file.
1 // Copyright (C) 2013 Lutz Foucar
2 
3 /**
4  * @file generic_factory.hpp contains a factory that can be used for any class
5  *
6  * @author Lutz Foucar
7  */
8 
9 #ifndef _GENERIC_FACTORY_
10 #define _GENERIC_FACTORY_
11 
12 #include <tr1/functional>
13 #include <tr1/memory>
14 #include <map>
15 #include <string>
16 
17 namespace cass
18 {
19 
20 /** @def macro for easier adding of the registrar class */
21 #define REGISTER(basename,derivedname) \
22  private: \
23  static const Registrar<basename,derivedname> reg;
24 
25 /** @def macro for easier defining the registrar class */
26 #define DEFINEREGISTER(basename,derivedname,key) \
27 const Registrar<basename,derivedname> derivedname::reg("key");
28 
29 
30 /** function to create an instance of a class
31  *
32  * creates an instance of Dervied using new and returns a shared_ptr object that
33  * is defined in the derived class.
34  *
35  * @tparam Derived the derived class
36  * @return shared pointer of Base class of Derived class
37  *
38  * @author Lutz Foucar
39  */
40 template <class Derived>
41 typename Derived::shared_pointer instanciator()
42 {
43  return typename Derived::shared_pointer(new Derived);
44 }
45 
46 /** function to create a singleton of a class
47  *
48  * the singleton will be created by calling the static member instance of
49  * the class. The class needs to provide this member. Also it needs to provide
50  * how the shared pointer is called
51  *
52  * @tparam Derived the derived class
53  * @return a shared pointer of the derived class type
54  *
55  * @author Lutz Foucar
56  */
57 template <class Derived>
58 typename Derived::shared_pointer singletoninstanciator()
59 {
60  return Derived::instance();
61 }
62 
63 /** Factory for creating shared_pointers of classes derived from a base class
64  *
65  * One can use this class to facilitate the factory pattern. Instead of having
66  * to add possible instanciatable derived classes at one point, one can use
67  * this factory and let the derived class register itself to the factory.
68  * To do this one can either use the helper struct cass::Registrar or call
69  * the static member function Factory::addType.
70  *
71  * @note The base class whose derived class should be instanciated through
72  * this factory need to typedef what the shared pointer to them looks
73  * like.
74  *
75  * @tparam Base The type of the base class.
76  *
77  * @author Lutz Foucar
78  */
79 template <class Base>
80 class Factory
81 {
82  /** define a shared pointer of the base class */
83  typedef typename Base::shared_pointer shared_pointer;
84 
85 public:
86  /** define a reference to this factory */
88 
89  /** define how the instanctiator function should look like */
90  typedef std::tr1::function<shared_pointer()> instanciator_t;
91 
92  /** define the map of instanciator functions */
93  typedef std::map<std::string,instanciator_t> instanciatorMap_t;
94 
95 public:
96  /** get an instance of the factory
97  *
98  * static function to make this a singleton. Creates a static instance of this
99  * class and returns a reference to it.
100  *
101  * @note if one wants to use this factory in the multithreadded part, one has
102  * to think about mutexing it.
103  *
104  * @return reference to this instance
105  */
106  static reference instance()
107  {
108  static Factory<Base> instance;
109  return instance;
110  }
111 
112  /** create an instance of the requested derived type
113  *
114  * looks up whether the requested type has been registered, if not throws an
115  * invalid_argument exception. If type is part of the map, then use the
116  * instanciator to create the instance. Return the instance in a shared_ptr
117  * object of the base class.
118  *
119  * @return shared_ptr object of the base class.
120  * @param type The type of the derived class that should be instanciated
121  */
122  shared_pointer create(const typename instanciatorMap_t::key_type & type)
123  {
124  using namespace std;
125  typename instanciatorMap_t::const_iterator it(_iMap.find(type));
126  if (it == _iMap.end())
127  throw invalid_argument("Factory::create(): Type '" + type +"' is not registered");
128  return (it->second)();
129  }
130 
131  /** register a derived type to the map
132  *
133  * @tparam Derived The type of the derived class
134  * @param type the Key that the type should have in the instanciator map
135  */
136  template <class Derived>
137  char addType(const typename instanciatorMap_t::key_type &type)
138  {
139  _iMap.insert(make_pair(type,&instanciator<Derived>));
140  return 0;
141  }
142 
143  /** register a derived singleton type to the map
144  *
145  * @tparam Derived The type of the derived class
146  * @param type the Key that the type should have in the instanciator map
147  */
148  template <class Derived>
149  char addSingletonType(const typename instanciatorMap_t::key_type &type)
150  {
151  _iMap.insert(make_pair(type,&singletoninstanciator<Derived>));
152  return 0;
153  }
154 
155 private:
156  /** map human readable names to instanciators for the object */
157  instanciatorMap_t _iMap;
158 };
159 
160 /** helper struct that will add Derived to the factory map
161  *
162  * @note put a static instance of this struct into the derived class
163  * implementation that should be registered. When the static variable is
164  * defined this constructor will automatically register the derived class
165  * to the instanciator map of the factory.
166  *
167  * @tparam Base the type of the base class
168  * @tparam Derived the type of the derived class
169  */
170 template<class Base, class Derived>
171 struct Registrar
172 {
173  /** define the factory */
175 
176  /** define a reference to the factory */
177  typedef typename factory_t::reference factory_r;
178 
179  /** constuctor
180  *
181  * register the derived class in the factorys instanciator map.
182  *
183  * @param type the type as a human readable string
184  */
185  Registrar(const typename factory_t::instanciatorMap_t::key_type &type)
186  {
187  factory_r factory(factory_t::instance());
188  factory.template addType<Derived>(type);
189  }
190 
191  /** constuctor
192  *
193  * register the derived singelton class in the factorys instanciator map.
194  *
195  * @param type the type as a human readable string
196  */
197  Registrar(const typename factory_t::instanciatorMap_t::key_type &type,bool)
198  {
199  factory_r factory(factory_t::instance());
200  factory.template addSingletonType<Derived>(type);
201  }
202 };
203 
204 }//end namespace cass
205 #endif
std::tr1::function< shared_pointer()> instanciator_t
define how the instanctiator function should look like
helper struct that will add Derived to the factory map
char addSingletonType(const typename instanciatorMap_t::key_type &type)
register a derived singleton type to the map
std::map< std::string, instanciator_t > instanciatorMap_t
define the map of instanciator functions
Derived::shared_pointer instanciator()
function to create an instance of a class
instanciatorMap_t _iMap
map human readable names to instanciators for the object
Base::shared_pointer shared_pointer
define a shared pointer of the base class
char addType(const typename instanciatorMap_t::key_type &type)
register a derived type to the map
STL namespace.
shared_pointer create(const typename instanciatorMap_t::key_type &type)
create an instance of the requested derived type
Factory< Base > factory_t
define the factory
factory_t::reference factory_r
define a reference to the factory
Derived::shared_pointer singletoninstanciator()
function to create a singleton of a class
Registrar(const typename factory_t::instanciatorMap_t::key_type &type)
constuctor
Factory< Base > & reference
define a reference to this factory
static reference instance()
get an instance of the factory
Registrar(const typename factory_t::instanciatorMap_t::key_type &type, bool)
constuctor
Factory for creating shared_pointers of classes derived from a base class.