Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Oct 1st, 2007, 10:13 PM   #1
Game_Ender
Professional Programmer
 
Game_Ender's Avatar
 
Join Date: May 2006
Location: Maryland, USA
Posts: 306
Rep Power: 3 Game_Ender is on a distinguished road
Critique of Policy Based Factory Pattern:

I am curious of what other people think of the following pattern:

The following is pretty powerful implementation of a factory pattern. Call it a "Maker" its based on a now lost article called "Industrial Strength Pluggable Object Factories". It supports customized return object types, object creational parameter types, and key types. It has the ability for you to customize how the object's key is extracted from the passed in parameters, how its looked up in the registry, and finally how its constructed.

The only thing I have not customized is the object registry, but with the flexibility of a std::mulimap, and its current tight coupling in the class it would be hard.

Note:
* It did take me many hours to write only 68 lines of highly template C++.
* This is also a good example of Policy based design
cpp Syntax (Toggle Plain Text)
  1. /*
  2.  * Copyright (C) 2007 Robotics @ Maryland
  3.  * Copyright (C) 2007 Joseph Lisee
  4.  * All rights reserved.
  5.  *
  6.  * Author: Joseph Lisee
  7.  * File: packages/pattern/include/Maker.h
  8.  *
  9.  * Under the BSD License
  10.  */
  11.  
  12. // STD Includes
  13. #include <map>
  14. #include <utility>
  15. #include <iostream>
  16. #include <cassert>
  17.  
  18. /*
  19.  This pattern is based on the "Industrial Strength Pluggable Factories"
  20.  article by Timothy R. Culp (with an added dose of policy based design)
  21. */
  22.  
  23.  
  24. /** Default MakerLookup policy. Returns first maker which maps to the given key.
  25.  */
  26. struct DefaultMakerLookup
  27. {
  28. template<class MapType>
  29. static typename MapType::mapped_type lookupMaker(MapType* registry,
  30. typename MapType::key_type key)
  31. {
  32. return registry->find(key)->second;
  33. }
  34. };
  35.  
  36. /** Default ObjectMaker policy. Uses virtual makeObject method on maker objects.
  37.  */
  38. template<class Object, class Param>
  39. struct DefaultObjectMaker
  40. {
  41. virtual ~DefaultObjectMaker() {};
  42.  
  43. /** Implemented by the subclasses of the Maker, creates the actual object */
  44. virtual Object makeObject(Param param) = 0;
  45.  
  46. template<class Maker>
  47. static typename Maker::ObjectType createObject(Maker* maker,
  48. typename Maker::ParamType param)
  49. {
  50. return maker->makeObject(param);
  51. }
  52. };
  53.  
  54.  
  55. /** Policy Based Object Creation Template
  56.  *
  57.  * This creates objects based on based in parameters use Maker objects
  58.  * registered to a specific key. It is templated based on the type of the
  59.  * object, parameter, and key. It also uses policies for extracting the key
  60.  * from the given parameters, finding the maker based from the multimap give
  61.  * the key, and finially creating the object using the found maker and the
  62.  * given parameter. @par
  63.  *
  64.  * Makers are registered in there constructor by calling the super class
  65.  * constrcutor with the desired key. Example:
  66.  * @code
  67.  
  68. struct StreamKeyExtractor
  69. {
  70.   static std::string extractKey(std::iostream& param)
  71.   {
  72.   std::string key;
  73.   param >> key;
  74.   return key;
  75.   }
  76. };
  77.  
  78. class Number
  79. {
  80. public:
  81.   virtual ~Number() {};
  82. };
  83.  
  84. class Int : public Number
  85. {
  86. public:
  87.   Int(int _val) : value(_val) {};
  88.  
  89.   int value;
  90. };
  91.  
  92. typedef Maker<Number*, // The type of object created by the maker
  93.   std::iostream&, // The parameter used to create the object
  94.   std::string, // The type of key used to register makers
  95.   StreamKeyExtractor> // Gets the key from the paramters
  96. NumberMaker;
  97.  
  98.  
  99. class IntMaker : public NumberMaker
  100. {
  101. public:
  102.   IntMaker() : NumberMaker("Int") {};
  103.   virtual Number* makeObject(std::iostream& param)
  104.   {
  105.   int value;
  106.   param >> value;
  107.   return new Int(value);
  108.   }
  109. private:
  110.   // Calls constructor to register the maker
  111.   static IntMaker registerThis;
  112. };
  113. // Needs to be in a cpp file to actually invoke the constructor
  114. IntMaker IntMaker::registerThis;
  115. };
  116.  
  117.  * @endcode
  118.  */
  119.  
  120. template<class Object, class Param, class Key,
  121. class KeyExtract,
  122. class MakerLookup = DefaultMakerLookup,
  123. class ObjectCreate = DefaultObjectMaker<Object, Param> >
  124.  
  125. class Maker : public KeyExtract,
  126. public MakerLookup,
  127. public ObjectCreate
  128. {
  129. public:
  130. typedef std::multimap<Key, Maker*> MakerMap;
  131. typedef typename MakerMap::const_iterator MakerMapIter;
  132.  
  133. typedef Object ObjectType;
  134. typedef Param ParamType;
  135. typedef Key MappedType;
  136.  
  137. private:
  138. Key m_key;
  139.  
  140. /** Returns the global registry for this maker
  141.   *
  142.   */
  143. static MakerMap* getRegistry()
  144. {
  145. // This line is run only once, avoids static initialization order issue
  146. static MakerMap* reg = new MakerMap();
  147. return reg;
  148. }
  149.  
  150. public:
  151.  
  152. /** This constructor which registers the maker class in the registry
  153.   *
  154.   * @remarks
  155.   * When you subclass this class you should place a static instance
  156.   * of the class in its own definition. Then just make sure to call
  157.   * the super classes default constructor with the name of the class.
  158.   *
  159.   * @param key
  160.   * The object that identifies the class in the registry.
  161.   */
  162. Maker(Key key) :
  163. m_key(key)
  164. {
  165. // Grab the registry (first use creates it on the heap)
  166. MakerMap* registry = getRegistry();
  167.  
  168. // Register Self
  169. registry->insert(make_pair(key, this));
  170. }
  171.  
  172. /** Unregisters the Maker, and cleans up registry if necessary
  173.   *
  174.   * @remarks
  175.   * If this is the last class in the registry, it will delete the
  176.   * global registry.
  177.   */
  178. virtual ~Maker()
  179. {
  180. MakerMap* registry = getRegistry();
  181.  
  182. // Remove self from registry
  183. registry->erase(m_key);
  184.  
  185. // Free up registry if we are the last in the registry
  186. if (0 == registry->size())
  187. delete registry;
  188. }
  189.  
  190. /** Creates a new object based on the given parameters
  191.   *
  192.   * This uses the KeyExtract policy to pull the key from the parameters.
  193.   * Then it looks up the proper maker with the lookupMaker policy using that
  194.   * key. The default one uses the first maker which maps to the key. Then
  195.   * it creates the object by using the ObjectCreat Policy. The defualt
  196.   * policy just uses the virtual makeObject function.
  197.   */
  198. static Object newObject(Param param)
  199. {
  200. Key key(KeyExtract::extractKey(param));
  201. Maker* maker = MakerLookup::lookupMaker(getRegistry(), key);
  202.  
  203. // TODO: raise an exception here
  204. assert(maker && "Could not find object to match given key");
  205. return ObjectCreate::createObject(maker, param);
  206. }
  207. };
__________________
Robotics @ Maryland AUV Team - Software Lead
Game_Ender is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 1:49 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC