Greetings, I don't often create threads on this board, however, I'm looking for some constructive criticism on an idea i've been toying around with for the past couple of days. I've written a small semi-complete (compilable) program to demonstrate the concept (I haven't actually implemented a "Factory" as such yet, i'm still attempting to design the Dictionary portion)
I'm trying to find a work-around for the way a factory is normally setup, either with a pre-written set of case statements, if/else statements, or a lookup table - My idea is that the lookup table can be automatically generated by a static data member's initialisation call to a constructor (Which happens before main() begins) - and the constructor for the static members may fill up my dictionary for me. I wish to avoid writing/changing long, cumbersome lookup tables every time I add a class to my hierarchy.
fact_dict.h
Code:
#ifndef FACT_DICT_H
#define FACT_DICT_H
#include <string>
#include <map>
class EntityBase;
typedef EntityBase* (*factory_t)();
class FactoryDictionary
{
typedef std::map< std::string, factory_t > edict_t;
edict_t edict;
FactoryDictionary() {};
FactoryDictionary(FactoryDictionary&) {};
public:
factory_t lookup_from_string(std::string);
static FactoryDictionary& get_dict();
bool insert(std::string, factory_t);
};
class DictionaryLogger
{
public:
DictionaryLogger(std::string, factory_t);
};
#ifdef DICT_SETUP_CLASS
#undef DICT_SETUP_CLASS
#endif
// DICT_SETUP_CLASS must be the first line in the class declaration
#define DICT_SETUP_CLASS \
public: \
static EntityBase* fact_dict_create__(); \
private: \
static const DictionaryLogger fact_dict_record__
#ifdef DICT_REGISTER_CLASS
#undef DICT_REGISTER_CLASS
#endif
// DICT_REGISTER_CLASS must go in the same file as the class implementation
#define DICT_REGISTER_CLASS(classname) \
EntityBase* classname::fact_dict_create__() \
{ \
return new classname; \
} \
const DictionaryLogger classname::fact_dict_record__ \
( std::string( #classname ), &classname::fact_dict_create__ )
class EntityBase // All classes recorded in dictionary must be derived from here.
{
public:
virtual std::string foo() =0;
};
#endif
fact_dict.cpp
Code:
#include <iostream>
#include <string>
#include <map>
#include <utility>
#include "fact_dict.h"
// Wrapper for singleton dictionary object.
FactoryDictionary& FactoryDictionary::get_dict()
{
static FactoryDictionary* fd = new FactoryDictionary();
return *fd;
}
bool FactoryDictionary::insert(std::string s, factory_t cf)
{
if (edict.find(s) == edict.end() )
{
std::pair<std::string, factory_t> p(s, cf);
edict.insert(p);
return 1;
}
else
{
std::cout << "ERROR! " << s << " DUPLICATE FOUND. \n";
exit(EXIT_FAILURE); //TODO: Exception Handling
}
}
factory_t FactoryDictionary::lookup_from_string(std::string s)
{
if (edict.find(s) == edict.end() )
{
std::cout << s << " not found\n";
return NULL;
}
else
return edict[s];
}
DictionaryLogger::DictionaryLogger(std::string s, factory_t creator)
{
FactoryDictionary::get_dict().insert(s,creator);
}
// Pure virtual test function
std::string EntityBase::foo()
{
return std::string ("This is the EntityBase \"foo\" \n");
}
test.cpp
Code:
#include <iostream>
#include <string>
#include <map>
#include <utility>
#include "fact_dict.h"
class EntityTest1 : public EntityBase
{
DICT_SETUP_CLASS;
public:
std::string foo();
};
DICT_REGISTER_CLASS(EntityTest1);
std::string EntityTest1::foo()
{
return std::string("This is the EntityTest1 \"foo\" \n");
}
int main()
{
FactoryDictionary& dictionary = FactoryDictionary::get_dict();
factory_t create_object = dictionary.lookup_from_string("EntityTest1");
EntityBase* eb = create_object();
std::cout << eb->foo();
delete eb;
}
I've used constructs in this which are slightly "evil". I'm still undecided whether to keep the macros - on one hand I like the 'clean' look it gives to my entity classes, and the convenience, on the other hand, it obfuscates some details - although these are only details which should really be of no importance to any part of the program except the factory.
I've also neglected to add any kind of templating so far (although later I probably will), since this is a work-in-progress, I want to get the basic structure laid out before i begin messing with templates (Of course, ideally, it would be nice to have a completely generic factory & dictionary)
I've no idea whether there are already existing patterns or conventions in place for this kind of thing (I suspect they are, and i've been re-inventing the wheel), if there are, then I would certainly appreciate anyone pointing them out, so that I may slope-off and do it 'properly'
Otherwise, if anyone's got any criticisms/ideas/flames, i'd like to hear them, too
Thanks for your time
Bench