Инициализация класса
От: remark Россия http://www.1024cores.net/
Дата: 20.11.05 15:33
Оценка:
Предлагается решение следующей проблемы:

Имеется интерфейс обработчика запроса:

struct IProcessor
{
    virtual void process() = 0;
};


Далее в программе имеется множество реализаций интерфейса для различных типов запросов. Проблема заключается в том как автоматически и масштабируемо поддерживать множество всех реализаций обработчиков запросов, т.е. автоматически иметь фабрику для всех обработчиков, иметь возможность вывести в интерфейс пользователя список имеющихся обработчиков и т.д.

Т.е. для реализации обработчика запроса необходима некая инициализация класса, в которой он мог бы добавить свой класс в список всех обработчиков запросов.

Основа решения — класс "инициализатор класса":
(версия под компилятор msvc 7.1 или выше, т.к. используются __if_exists и __declspec(selectany), на других компиляторах возможно имеются аналоги)

#pragma once

// ClassInitializer.h
#pragma once

/**    Инициализатор класса */
template<typename Class>
class ClassInitializer
{
private:
    /**    Вспомогательная структара */
    struct Initializer
    {
        Initializer()
        {
            // необходимо, т.к. не каждый класс хочет явно определять 
            // и инициализацию и деинициализацию класса
            __if_exists(Class::initializeClass)
            {
                Class::initializeClass();
            }
        }

        ~Initializer()
        {
            // необходимо, т.к. не каждый класс хочет явно определять 
            // и инициализацию и деинициализацию класса
            __if_exists(Class::uninitializeClass)
            {
                Class::uninitializeClass();
            }
        }

        void fake()
        {}
    };

    static Initializer m_initializer;

protected:
    ClassInitializer()
    {
        // Необходимо для борьбы с ленивой генерацией кода для шаблонов
        m_initializer.fake();
    }
};


template<typename Class>
__declspec(selectany)
typename ClassInitializer<Class>::Initializer 
ClassInitializer<Class>::m_initializer;



Необходимо отнаследоваться от класса ClassInitializer и инстанциировать его собственным классом. Далее необходимо определить публичные статические функции initializeClass() и uninitializeClass(), которые будут вызываться для класса один раз вначале и один раз в конце работы программы (т.е. конструктор и деструктор для метакласса).

Полностью весь код приводить не буду (он достаточно тривиален). Вот определение базового класса для всех обработчиков (этот класс отвечает за всю работу по поддержке списка всех обработчиков):

template<typename Derived>
class Processor : public IProcessor, private ClassInitializer<Derived>
{
public:
    static void initializeClass()
    {
        ProcessorFactory::addWrapper(new CProcessorWrapper<Derived>);
    }

    static void uninitializeClass()
    {
        ProcessorFactory::removeWrapper(Derived::CODE);
    }
};



Сам конкретный обработчик выглядит примерно так:

class Processor1 : public Processor<Processor1>
{
public:
    static const int REQUEST_TYPE = 1;

    Processor1()
    {}

    virtual void process()
    {}
};


Использование всего этого дела выглядит примерно так:

void processRequest(int RequestType)
{
    IProcessorWrapper* wrapper = ProcessorFactory::getWrapper(RequestType);
    log << "Request: type = " << wrapper->getTypeName();
    IProcessor* processor = wrapper->create();
    processor->process();
}

void displayProcessorsList()
{
    ProcessorList list = ProcessorFactory::getList();
    display(list);
}



Всё что нужно для добавления в программу нового обработчика — определить его класс — далее вся его поддержка при обработке запросов и в интерфейсе пользователя происходит автоматически.


Обработка запросов приведена в качестве примера использования, область применения этого приёма, конечно, гораздо шире. Его можно применять не только для поддержки списка типов, но и для выполнения некой разовой инициализации для одного класса.

Пока, правда, имеется нерешённая проблема — у производного от ClassInitializer (листового) класса обязательно должен быть констуктор. Иначе весь этот механизм не вступит в силу. В данном примере наличие коструктора можно форсировать наличием не-дефаултного конструктора у класса Processor.

Пока ничего подобного в литературе не встречал (ни у Саттера, ни у (как ни странно ) Александреску).

Если у кого есть какие замечания/предложения/вопросы/комментарии/ссылки — прошу сюда.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.