Thread: static member initialisation with factory pattern

  1. #1
    Registered User
    Join Date
    Feb 2006
    Posts
    312

    static member initialisation with factory pattern

    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
    Last edited by Bench82; 08-31-2006 at 06:23 PM.

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
    #ifdef DICT_SETUP_CLASS
    #undef DICT_SETUP_CLASS
    #endif
    #define DICT_REGISTER_CLASS(classname) \
    I think you can just #define something regardless of whether it already exists or not, so you may not need that #undef.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Registered User
    Join Date
    Feb 2006
    Posts
    312
    Thanks, you could well be right. Also, the chances of that name actually being already used are prpbably quite slim. I guess its pessimistic programming

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Here's a thread I started titled "Do you need to #undef something that's already defined?": http://cboard.cprogramming.com/showthread.php?t=75388

    It looks like you do need the #undef. However, I don't think you need to #ifdef; I think you can #undef something even if it isn't already defined. (For now you might as well just leave it as it is, though.)
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. uploading file to http server via multipart form data
    By Dynamo in forum C++ Programming
    Replies: 1
    Last Post: 09-03-2008, 04:36 AM
  2. compilation problems with static data member
    By viral612 in forum C++ Programming
    Replies: 1
    Last Post: 08-13-2008, 06:55 AM
  3. LNK2001 ERROR!!! need help
    By lifeafterdeath in forum C++ Programming
    Replies: 7
    Last Post: 05-27-2008, 05:05 PM
  4. Static & Data Member
    By ecoliteracy in forum C++ Programming
    Replies: 1
    Last Post: 04-16-2007, 08:46 PM
  5. static member functions
    By DJ81 in forum C++ Programming
    Replies: 1
    Last Post: 03-26-2002, 06:20 AM