/* Author: Marco Costalba (C) 2007 This is a simple but powerful object factory.*/#ifndef SIMPLE_FACTORY_HPP #define SIMPLE_FACTORY_HPP
#include <map>
#include <string>
/* To get an object of a given class from the factory you need first to register the class against the factory, passing a class identifier. Interface is defined by these static methods bool Factory<Base>::register_class<Derived, ArgType = void>(KeyRef key, FnPtr = NULL); void Factory<Base>::unregister(str_ref ident); Base* Factory<Base>::object(str_ref ident, ArgType ctor_arg = NULL) Where: - 'Base' is the base class, there is one factory each base class - 'Derived' is a class that inherits 'Base' - 'ArgType' is the type of the argument passed to object constructor, if not supplied then default object constructor will be called. - 'KeyRef' is a const string reference used to query the factory for objects, a common choice for 'key' value is the name of the class. - 'FnPtr' it's a pointer to an user custom function with signature Derived* (*fnPtr) (ArgType) This function, if supplied, will be used instead of the default one to actually create the object. Default one is defined as: Derived* def_ctor(ArgType ctor_arg) { return new Derived(ctor_arg); } Note that in case FnPtr is supplied and custom function requires an argument is mandatory to set the corresponding ArgType in template parameters or a compile error will result. This enforces compile time type checking. And now the implementation...*/namespace simple_factory {
typedef std::string Key; // using std::string as key typetypedefconst Key& KeyRef;
struct NoArg {};
/* Traits to deal with custom creator function signature */template<class Derived, typename Arg> struct FnPtr { typedef Derived* (*type)(Arg); };
template<class Derived> struct FnPtr<Derived, NoArg> { typedef Derived* (*type)(); };
/* Traits to avoid hidden copies in parameters passing */template<typename T> struct Best { typedef T& type; };
template<typename T> struct Best<T&> { typedef T& type; };
template<typename T> struct Best<T*> { typedef T* type; };
/* Traits to strip const and reference qualifiers */template<typename T> struct Naked { typedef T type; };
template<typename T> struct Naked<const T> { typedef T type; };
template<typename T> struct Naked<T&> { typedef T type; };
template<typename T> struct Naked<const T&> { typedef T type; };
/* Not accessible private singleton class that implements the factory, it * is not possible to use it directly but user must access through 'Factory' */template<class Base> class Factory_p { // singleton class, one each base classFactory_p() {}
Factory_p(const Factory_p&);
Factory_p& operator=(const Factory_p&);
~Factory_p() {
for(ConstIter it = creators.begin(); it != creators.end(); ++it)
delete (*it).second;
}
/* 'StorableType' is the common base class to store pointers * to different type of creators, dynamic_cast<> at runtime * will be used to check the (hidden) derived type */class StorableType { public:
virtual ~StorableType() {}
};
typedef std::multimap<Key, const StorableType*> Container;
typedeftypename Container::iterator Iter;
typedeftypename Container::const_iterator ConstIter;
Container creators;
/* 'CreatorBase' is subclassed from StorableType and identifies * an unique argument type. Used by runtime argument checking. */template<typename Arg>
class CreatorBase : public StorableType { public:
virtual Base* doCreate(typename Best<Arg>::type) const = 0;
};
/* 'Creator' is subclassed from 'CreatorBase' and wraps the * actual object creator method or custom function pointer. */template<class Derived, typename Arg, typename FnType>
class Creator : public CreatorBase<Arg> { public:
Creator(FnType fn) : createFn(fn) {}
virtual Derived* doCreate(typename Best<Arg>::type v) const {
return (createFn ? createFn(v) : newDerived(v));
}
FnType createFn;
};
/* Following the specializations of 'Creator' according to the * number of arguments. There is one specialization each c'tor * argument number. *//* Zero arguments case */template<class Derived, typename FnType>
class Creator<Derived, NoArg, FnType> : public CreatorBase<NoArg> { public:
Creator(FnType fn) : createFn(fn) {}
virtual Derived* doCreate(typename Best<NoArg>::type) const {
return (createFn ? createFn() : newDerived());
}
FnType createFn;
};
/* Some helpers that deal with 'CreatorBase' objects */template<typename Arg>
const CreatorBase<Arg>* checkType(const StorableType* p) const {
// check c'tor argument type at runtimereturndynamic_cast<const CreatorBase<Arg>*>(p);
}
template<typename Arg>
const CreatorBase<Arg>* find(KeyRef nm) const {
std::pair<ConstIter, ConstIter> r = creators.equal_range(nm);
for (ConstIter it = r.first; it != r.second; ++it) {
const CreatorBase<Arg>* p = this->checkType<Arg>((*it).second);
if (p) return p;
}
return NULL;
}
protected: // only Factory can use Factory_pstatic Factory_p& instance() {
static Factory_p p_instance;
return p_instance;
}
public:
/* These methods can be called only from Factory_p::instance(), * no problem in declaring 'public' because only Factory * can access Factory_p<Base>::instance() */template<typename RowArg>
Base* doObject(KeyRef nm, typename Best<RowArg>::type v) const {
typedeftypename Naked<RowArg>::type Arg;
const CreatorBase<Arg>* p = this->find<Arg>(nm);
return (p ? p->doCreate(v) : NULL);
}
template<class Derived, typename RowArg, typename FnType>
bool doRegister(KeyRef nm, FnType fn) {
typedeftypename Naked<RowArg>::type Arg;
if (this->find<Arg>(nm)) // (name, argument) pair already exsistingreturnfalse;
creators.insert(std::make_pair(nm, new Creator<Derived, Arg, FnType>(fn)));
returntrue;
}
template<typename RowArg>
bool doUnregister(KeyRef nm) {
typedeftypename Naked<RowArg>::type Arg;
std::pair<Iter, Iter> r = creators.equal_range(nm);
for (Iter it = r.first; it != r.second; ++it) {
if (this->checkType<Arg>((*it).second)) {
delete (*it).second;
creators.erase(it);
returntrue; // can be only one
}
}
returnfalse;
}
};
/* Class 'Factory' is the only public interface to deal * with the factory. * * It has only static methods so simply declaring * (without defining) the constructor private seems * enough to prevent any possible instantation. * * Q: Why 'Factory' instead of using only 'Factory_p' ? * * A: Because accessing Factory_p directly has an ugly and * involved syntax, 'Factory' is much easier to use. * So because the 'official' interface is Factory, * users should not access Factory_p::instance(), * that's the reason this method is protected. Also using * some external friend template functions does not improve * the syntax for the user and also yields to have another * file for function definitions. */template<class Base> class Factory : private Factory_p<Base> {
Factory(); // prevent instantationpublic:
/* No c'tor argument overloads */static Base* object(KeyRef nm) {
NoArg a; // seems needed, doObject() does not accept temporaries????return Factory_p<Base>::instance(). template doObject<NoArg>(nm, a);
}
template<class Derived>
static bool register_class(KeyRef nm, typename FnPtr<Derived, NoArg>::type fn = NULL) {
typedeftypename FnPtr<Derived, NoArg>::type FnType;
return Factory_p<Base>::instance(). template doRegister<Derived, NoArg, FnType>(nm, fn);
}
static bool unregister(KeyRef nm) {
return Factory_p<Base>::instance(). template doUnregister<NoArg>(nm);
}
/* One c'tor argument overloads */template<typename RowArg>
static Base* object(KeyRef nm, RowArg v) {
return Factory_p<Base>::instance(). template doObject<RowArg>(nm, v);
}
template<class Derived, typename RowArg>
static bool register_class(KeyRef nm, typename FnPtr<Derived, RowArg>::type fn = NULL) {
typedeftypename FnPtr<Derived, RowArg>::type FnType;
return Factory_p<Base>::instance(). template doRegister<Derived, RowArg, FnType>(nm, fn);
}
template<typename RowArg>
static bool unregister(KeyRef nm) {
return Factory_p<Base>::instance(). template doUnregister<RowArg>(nm);
}
};
}
#endif