Сам паттер фабрики и другие описан в http://rsdn.ru/res/book/oo/design_patterns.xml
В кратце задача:
Иметь способ в run-time создавать конкретный тип класса определенной иерархии по некому индентификатору. Идентификатор может быть чем угодно - строка, число, другой класс. Все что угодно что можно сравнивать (есть operator == и operator <).
Использование примерно такое:
BaseClass* pConcreteClass = someFactoryObject.createConcreteClass( "Derived" );
Сама фабрика отлично разжована в книжке Александреску Modern C++ Design.
Вот ее исходный код ( в моем исполнении, но сама идея полностью та):
Код: Выделить всё
//AbstractProduct - is the base class of the hierarchy for which you provide the object factory
//IdentifierType - is the type of the "cookie" that represents a type in the hierarchy. It has to be
// an ordered type (able to be stored in a std::map). Commonly used identifier types are strings
// and integral types.
//ProductCreator is the callable entity that creates objects. This type must support
// operator(), taking no parameters and returning a pointer to AbstractProduct. A
// ProductCreator object is always registered together with a type identifier.
//FactoryBase is the base class for factory. Must implement a method post_create for post creation object processing.
// see default_base
template< typename AbstractProduct ,
typename IdentifierType,
typename ProductCreator = AbstractProduct*(*)()
class generic_factory
{
typedef std::map< IdentifierType , ProductCreator > creators_t;
creators_t creators_;
generic_factory(void){}
generic_factory(generic_factory&);
generic_factory& operator=(const generic_factory&);
public:
typedef typename IdentifierType identifier_t;
typedef typename boost::remove_pointer<AbstractProduct>::type product_t;
typedef typename boost::call_traits< IdentifierType >::param_type identifier_param_t;
typedef typename boost::add_pointer<product_t>::type product_pnt_t;
//singleton pattern
static generic_factory& instance()
{
static generic_factory factory_;
return factory_;
}
//!perform class registration, return true if class succssesfully registered
//! \param class_id identifier of class
//! \param creator function to create class
bool register_class( identifier_param_t class_id , ProductCreator creator )
{
return creators_.insert( std::make_pair(class_id , creator) ).second;
}
//!create the class by id. return pointer to the base class
//! \param class_id class identifier
//! \return pointer to created class, 0 if identifier is invalid
product_pnt_t create( identifier_param_t class_id )
{
creators_t::const_iterator it = creators_.find( class_id );
if( it != creators_.end())
{
product_pnt_t pnt = (it->second)();
return pnt;
}
return 0;
}
};Итак, у нас есть фабрика-синглетон и есть два метода у нее - register_class & create.
Первый "регистрирует" класс, т.е. связывает идентификатор с конкретным ProductCreator'ом. В случае по-умолчанию, ProductCreator - это обычная С-шная функция которая просто делает new на конкретный тип.
Метод create непосредтсвенно ищет по идентификатору конкретный Creator и вызывает его - все просто как тапочки.
Пример использования всего этого хозяйства:
Код: Выделить всё
struct Base
{
...
};
struct Der1: public Base
{
....
};
struct Der2: public Base
{
....
};
typedef enum BaseID{ idDer1,idDer2 };
typedef generic_factory< Base , BaseID > MyFactory;
в .cpp файле:
Base* createDir1()
{
return new Dir1;
}
Base* createDir2()
{
return new Dir2;
}
где-то еще в коде приложения:
MyFactory::instance().register_class( idDer1 , &createDir1 );
MyFactory::instance().register_class( idDer2 , &createDir2 );Как видим выходит много избыточного кода, который по сути одинаковый + который надо не забывать вызывать в правельное время (т.е. register должен быть раньше create'a) и другие проблемы, например избыточность явная.
Упростить это и есть задача
Итак задача, очень даже реальная в жизни, когда я ее реализовал, удалось упростить и реально улучшить многие части нашего приложения.
Условия:
1) Сделать механизм автоматической регистрации классов. Т.е. убрать необходимость думать и месте и времени вызова register_class
2) В _нашем_ приложении оказалось много иерархий классов, которые сами по себе маленькие, но их количество весьма велико. На каждый писать Creator& вызов register_class - ужасная трата времени и большой объем исходников.
3) Выполнить это типо-безопасно.
4) _НЕ_ использовать макросы С.
В идеале решение должно быть такое:
в любом месте кода перечисляем список всех классов, входящих в конкретную иерархию и говорим один раз зарегестрировать весь список.
Если ответов совсем не будет, опубликую ответ быстро, если завяжеться дискуссия (конструктивная), то подожду