Friday, November 26, 2010

Factory with registerable and configurable units..

One of the most common patterns used in software a factory. The ideal factory has sub units that can register with the main factory using one or more keywords.

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/TypeDescription
KeyThe description/tag/id for the factory
RegItemBaseThe Factory Registration generic entry
BaseThe Factory output class
RegFactoryThe Factory
RegItemAn item to register with the factory, without any parameters
RegItemParamAn item to register with the factory, without a single parameter
AThe First demo class
BThe 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