Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

FamilyFactory.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_FamilyFactory_h_
00003 #define INCLUDED_FamilyFactory_h_
00004 
00005 #include "Factories.h"
00006 #include <string>
00007 #include <map>
00008 #include <set>
00009 #include <iostream>
00010 
00011 //! A class which can track a set of subclass types (with shared base class FamilyT), generating new instances on demand based on some form of identifier (the NameT template parameter)
00012 /*! Register your class via registerType() or registerFactory(), and then instantiate it later
00013  *  with a call to create().  Note that you have a variety of options to control how the product
00014  *  is constructed via your choice of the FactoryBaseT and FactoryT template parameters.
00015  *
00016  *  The FactoryBaseT defines the interface, exposing available factory functor calls which return
00017  *  the shared base class.  The FactoryT is a template template parameter which indicates
00018  *  the factory to be created for each call to registerType().  This should take the type to be
00019  *  produced as its template parameter, and implement the interface expected by FactoryBaseT.
00020  *
00021  *  By default, FamilyFactory looks for a type named 'Factory' within the FactoryBaseT namespace.
00022  *  This parameter would be ignored if you only ever call registerFactory, and pass your own factory
00023  *  instances.
00024  *
00025  *  A cute way to automatically trigger type registration is to define a static member of your class,
00026  *  and then call registerType() or registerFactory() for its initialization.
00027  *
00028  *  See Factories.h for some basic factory types. */
00029 template<class FamilyT, typename NameT=std::string, class FactoryBaseT=Factory0Arg<FamilyT>, template<class U> class FactoryT=FactoryBaseT::template Factory>
00030 class FamilyFactory {
00031 public:
00032   //! allows indirect access to the product family type
00033   typedef FamilyT FamilyType;
00034   //! allows indirect access to the product class name type
00035   typedef NameT NameType;
00036   //! allows indirect access to the factory base class
00037   typedef FactoryBaseT FactoryBaseType;
00038   //! allows indirect access to create factory classes
00039   template<class T> struct FactoryType : FactoryT<T> {};
00040   
00041   //! default constructor
00042   FamilyFactory() : factories() {}
00043   
00044   //! destructor
00045   virtual ~FamilyFactory() {
00046     for(typename factories_t::iterator it=factories.begin(); it!=factories.end(); ++it)
00047       delete it->second;
00048     factories.clear();
00049   }
00050 
00051   //! returns a singleton factory for the current template arguments... be careful that clients use the same templates as those used to register
00052   static FamilyFactory& getRegistry() { static FamilyFactory registry; return registry; }
00053   
00054   //! clears @a types and fills in the currently registered type identifiers
00055   template<typename N> void getTypeNames(std::set<N>& types) const;
00056   
00057   //! returns the number of currently registered type identifiers
00058   unsigned int getNumTypes() const { return factories.size(); }
00059   
00060   //! creates a factory for the specified type from FactoryT and registers it as @a type
00061   template<typename T> const NameT& registerType(const NameT& type) { return registerFactory(type,new FactoryT<T>); }
00062   
00063   //! registers the specified factory for producing objects known by @a type; FamilyFactory assumes responsibilty for deallocation of @a f
00064   const NameT& registerFactory(const NameT& type, FactoryBaseT* f);
00065   
00066   //! requests a new instance of the specified @a type be created, without passing any arguments to the factory
00067   /*! Note that the factory interface chosen by FactoryBaseT may not actually provide such a call! */
00068   FamilyT* create(const NameT& type) const { FactoryBaseT * f=lookupFactory(type); return f ? (*f)() : NULL; }
00069   
00070   //! requests a new instance of the specified @a type be created, passing a single argument to the factory
00071   /*! Note that the factory interface chosen by FactoryBaseT may not actually provide such a call! */
00072   template<typename A1>
00073   FamilyT* create(const NameT& type, const A1& a1) const { FactoryBaseT * f=lookupFactory(type); return f ? (*f)(a1) : NULL; }
00074   
00075   //! requests a new instance of the specified @a type be created, passing two arguments to the factory
00076   /*! Note that the factory interface chosen by FactoryBaseT may not actually provide such a call! */
00077   template<typename A1, typename A2>
00078   FamilyT* create(const NameT& type, const A1& a1, const A2& a2) const { FactoryBaseT * f=lookupFactory(type); return f ? (*f)(a1,a2) : NULL; }
00079   
00080   //! requests a new instance of the specified @a type be created, passing three arguments to the factory
00081   /*! Note that the factory interface chosen by FactoryBaseT may not actually provide such a call! */
00082   template<typename A1, typename A2, typename A3>
00083   FamilyT* create(const NameT& type, const A1& a1, const A2& a2, const A3& a3) const { FactoryBaseT * f=lookupFactory(type); return f ? (*f)(a1,a2,a3) : NULL; }
00084   
00085 protected:
00086   //! utility function to see if @a type has been registered and return it, or NULL if not found
00087   FactoryBaseT* lookupFactory(const NameT& type) const;
00088     
00089   //! type of #factories
00090   typedef std::map<NameT,FactoryBaseT*> factories_t;
00091   factories_t factories; //!< storage for type identifier to factory mapping
00092 };
00093 
00094 template<class FamilyT, typename NameT, class FactoryBaseT, template<class U> class FactoryT>
00095 template<typename N>
00096 void FamilyFactory<FamilyT,NameT,FactoryBaseT,FactoryT>::getTypeNames(std::set<N>& types) const {
00097   types.clear();
00098   for(typename factories_t::const_iterator it=factories.begin(); it!=factories.end(); ++it)
00099     types.insert(it->first);
00100 }
00101 
00102 template<class FamilyT, typename NameT, class FactoryBaseT, template<class U> class FactoryT>
00103 const NameT& FamilyFactory<FamilyT,NameT,FactoryBaseT,FactoryT>::registerFactory(const NameT& type, FactoryBaseT* f) {
00104     typename factories_t::const_iterator it=factories.find(type);
00105     if(it!=factories.end()) {
00106       std::cerr << "WARNING: Type " << type << " was already registered!  Overwriting previous..."  << std::endl;
00107       delete it->second;
00108     }
00109     factories[type]=f;
00110     return type;
00111 }
00112 
00113 template<class FamilyT, typename NameT, class FactoryBaseT, template<class U> class FactoryT>
00114 FactoryBaseT* FamilyFactory<FamilyT,NameT,FactoryBaseT,FactoryT>::lookupFactory(const NameT& type) const {
00115   typename factories_t::const_iterator it=factories.find(type);
00116   if(it==factories.end())
00117     return NULL;
00118   return it->second;
00119 }
00120 
00121 /*! @file
00122  * @brief 
00123  * @author Ethan Tira-Thompson (ejt) (Creator)
00124  */
00125 
00126 #endif

Tekkotsu v5.1CVS
Generated Mon May 9 04:58:38 2016 by Doxygen 1.6.3