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