The holy grail implementation is the self-registering factory, where the mere definition of the class causes it to register with the Factory. This is not really not really possible in C++ due to the limited RTT typing and introspection of the language. However you can do some 1 liner tricks to get the item to install at startup, such as static/local variables, or an instance function.
Below is a Factory that utilizes its registration to store the keyword, Type and some construction parameters for a factory. Thus allowing repeated of the same type with customized default parameters.
A brief class overview is
Class/Type | Description |
---|---|
Key | The description/tag/id for the factory |
RegItemBase | The Factory Registration generic entry |
Base | The Factory output class |
RegFactory | The Factory |
RegItem | An item to register with the factory, without any parameters |
RegItemParam | An item to register with the factory, without a single parameter |
A | The First demo class |
B | The Second demo class |
#include <iostream> #include <map> using namespace std; /***************************************************** * Factory with registering methods *****************************************************/ typedef string Key; class Base; class RegItemBase { public: RegItemBase(Key _key) : key(_key) {} virtual Base* construct() const = 0; virtual void print() const = 0; virtual const Key keyword() const { return key; } private: Key key; }; typedef map<Key,RegItemBase*> KeyRegItemMap; class Base { public: virtual const RegItemBase* getReg() const = 0; virtual const Key keyword() const { return getReg()->keyword(); } virtual void print() const { cout << keyword() << endl; } virtual void bark() const { cout << "...." << endl; } }; class RegFactory { public: static RegFactory* getInstance() { static RegFactory* instance = new RegFactory(); return instance; } void add(RegItemBase* item) { items[item->keyword()] = item; } Base* construct(Key key) { KeyRegItemMap::const_iterator bit = items.find(key); if(bit != items.end()) return bit->second->construct(); return NULL; } void listAll() { cout << "Registered items:" << endl; KeyRegItemMap::const_iterator bit; for(bit = items.begin(); bit != items.end(); bit++) { cout << " " << bit->second->keyword() << endl; } cout << "Registered items DONE" << endl; } protected: RegFactory() {} private: KeyRegItemMap items; }; template <class TempType> class RegItem : public RegItemBase { public: typedef TempType Type; RegItem(const Key _key) : RegItemBase(_key) { cout << "Registering key: " << _key << endl; RegFactory::getInstance()->add(this); } virtual Base* construct() const { return new Type(); } virtual void print() const { cout << keyword() << endl; } }; template <class TempType> class RegItemParam : public RegItemBase { public: typedef TempType Type; RegItemParam(const Key _key, string _param) : RegItemBase(_key), param(_param) { cout << "Registering key: " << _key << endl; RegFactory::getInstance()->add(this); } virtual Base* construct() const { return new Type(param); } virtual void print() const { cout << keyword() << endl; } private: string param; }; /***************************************************** * Specific Classes to register *****************************************************/ class A : public Base { public: static RegItemBase* reg() { static RegItemBase* regItem = (RegItemBase*)new RegItem<A>("A"); return regItem; } virtual RegItemBase* getReg() const { return A::reg(); } virtual void bark() const { cout << "ruff" << endl; } protected: friend class RegItem<A>; A() {} }; class B: public Base { public: static RegItemBase* reg() { static RegItemBase* regItem = (RegItemBase*)new RegItemParam<B>("B", "red"); static RegItemBase* regItem2 = (RegItemBase*)new RegItemParam<B>("C", "green"); return regItem; } virtual RegItemBase* getReg() const { return B::reg(); } virtual void bark() const { cout << "woof " << param << endl; } protected: friend class RegItemParam<B>; B(string _param) : param(_param) {} string param; }; int main() { //setup regs... A::reg(); B::reg(); //list types.. RegFactory::getInstance()->listAll(); Base* a = RegFactory::getInstance()->construct("A"); a->print(); a->bark(); Base* b = RegFactory::getInstance()->construct("B"); b->print(); b->bark(); Base* c = RegFactory::getInstance()->construct("C"); c->print(); c->bark(); }
http://accu.org/index.php/journals/597
No comments:
Post a Comment