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   //! clears @a types and fills in the currently registered type identifiers
00052   void getTypeNames(std::set<NameT>& types) const;
00053   
00054   //! returns the number of currently registered type identifiers
00055   unsigned int getNumTypes() const { return factories.size(); }
00056   
00057   //! creates a factory for the specified type from FactoryT and registers it as @a type
00058   template<typename T> const NameT& registerType(const NameT& type) { return registerFactory(type,new FactoryT<T>); }
00059   
00060   //! registers the specified factory for producing objects known by @a type; FamilyFactory assumes responsibilty for deallocation of @a f
00061   const NameT& registerFactory(const NameT& type, FactoryBaseT* f);
00062   
00063   //! requests a new instance of the specified @a type be created, without passing any arguments to the factory
00064   /*! Note that the factory interface chosen by FactoryBaseT may not actually provide such a call! */
00065   FamilyT* create(const NameT& type) const { FactoryBaseT * f=lookupFactory(type); return f ? (*f)() : NULL; }
00066   
00067   //! requests a new instance of the specified @a type be created, passing a single argument to the factory
00068   /*! Note that the factory interface chosen by FactoryBaseT may not actually provide such a call! */
00069   template<typename A1>
00070   FamilyT* create(const NameT& type, const A1& a1) const { FactoryBaseT * f=lookupFactory(type); return f ? (*f)(a1) : NULL; }
00071   
00072   //! requests a new instance of the specified @a type be created, passing two arguments to the factory
00073   /*! Note that the factory interface chosen by FactoryBaseT may not actually provide such a call! */
00074   template<typename A1, typename A2>
00075   FamilyT* create(const NameT& type, const A1& a1, const A2& a2) const { FactoryBaseT * f=lookupFactory(type); return f ? (*f)(a1,a2) : NULL; }
00076   
00077   //! requests a new instance of the specified @a type be created, passing three arguments to the factory
00078   /*! Note that the factory interface chosen by FactoryBaseT may not actually provide such a call! */
00079   template<typename A1, typename A2, typename A3>
00080   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; }
00081   
00082 protected:
00083   //! utility function to see if @a type has been registered and return it, or NULL if not found
00084   FactoryBaseT* lookupFactory(const NameT& type) const;
00085     
00086   //! type of #factories
00087   typedef std::map<NameT,FactoryBaseT*> factories_t;
00088   factories_t factories; //!< storage for type identifier to factory mapping
00089 };
00090 
00091 template<class FamilyT, typename NameT, class FactoryBaseT, template<class U> class FactoryT>
00092 void FamilyFactory<FamilyT,NameT,FactoryBaseT,FactoryT>::getTypeNames(std::set<NameT>& types) const {
00093   types.clear();
00094   for(typename factories_t::const_iterator it=factories.begin(); it!=factories.end(); ++it)
00095     types.insert(it->first);
00096 }
00097 
00098 template<class FamilyT, typename NameT, class FactoryBaseT, template<class U> class FactoryT>
00099 const NameT& FamilyFactory<FamilyT,NameT,FactoryBaseT,FactoryT>::registerFactory(const NameT& type, FactoryBaseT* f) {
00100     typename factories_t::const_iterator it=factories.find(type);
00101     if(it!=factories.end()) {
00102       std::cerr << "WARNING: Type " << type << " was already registered!  Overwriting previous..."  << std::endl;
00103       delete it->second;
00104     }
00105     factories[type]=f;
00106     return type;
00107 }
00108 
00109 template<class FamilyT, typename NameT, class FactoryBaseT, template<class U> class FactoryT>
00110 FactoryBaseT* FamilyFactory<FamilyT,NameT,FactoryBaseT,FactoryT>::lookupFactory(const NameT& type) const {
00111   typename factories_t::const_iterator it=factories.find(type);
00112   if(it==factories.end())
00113     return NULL;
00114   return it->second;
00115 }
00116 
00117 /*! @file
00118  * @brief 
00119  * @author Ethan Tira-Thompson (ejt) (Creator)
00120  *
00121  * $Author: ejt $
00122  * $Name: tekkotsu-4_0 $
00123  * $Revision: 1.3 $
00124  * $State: Exp $
00125  * $Date: 2007/11/10 22:58:09 $
00126  */
00127 
00128 #endif

Tekkotsu v4.0
Generated Thu Nov 22 00:54:53 2007 by Doxygen 1.5.4