Автоматическая регистрация статических фабрик объектов внутри модулей dll с помощью метапрограммирования или других - PullRequest
0 голосов
/ 19 июля 2011

В проекте, над которым я работаю, я хочу поместить классы в dll, которые будут инициализированы абстрактной фабрикой и включены посредством композиции в объекты в основной программе. Цель состоит в том, чтобы позволить пользователям создавать свои собственные модули dll и таким образом добавлять свои собственные функциональные возможности. Сам модуль dll должен быть максимально простым; в идеале он будет содержать классы функциональности и их базовый класс. Пользователь имеет доступ только к источнику для dll, а не к основной программе или фабрике.

Я нашел некоторый код для абстрактной фабрики на codeproject.com, который мне кажется довольно хорошим. Вот пример кода:

Код:

// Templates for the generic factory and factory plant
template <class BT>
class FactoryPlant
   {
   public:
      FactoryPlant() {}
      virtual ~FactoryPlant() {}
      virtual BT *createInstance() = 0;
   };

template <class BT,class ST>
class Factory : public FactoryPlant<BT>
   {
   public:
      Factory() {}
      virtual ~Factory() {}
      virtual BT *createInstance() {return new ST;}
   };


// Our sample classes
class SimpleBaseClass
   {
   public:
      virtual int              getValue()          = 0;
      virtual void             setValue(int value) = 0;
      typedef FactoryPlant<SimpleBaseClass> SimpleBaseClassFactory;
   };

class SimpleClass1 : public SimpleBaseClass
   {
   public:
      int  getValue()          {return m_value;}
      void setValue(int value) {m_value = value;}
      static Factory<SimpleBaseClass,SimpleClass1> myFactory;
   private:
      int m_value;
   };
Factory<SimpleBaseClass,SimpleClass1> SimpleClass1::myFactory;

class SimpleClass2 : public SimpleBaseClass
   {
   public:
      int  getValue()          {return m_value*100;}
      void setValue(int value) {m_value = value;}
      static Factory<SimpleBaseClass,SimpleClass2> myFactory;
   private:
      int m_value;
   };
Factory<SimpleBaseClass,SimpleClass2> SimpleClass2::myFactory;

// Some method that might need to create an instance
SimpleBaseClass *someMethod (std::map<int,SimpleBaseClass::SimpleBaseClassFactory *> factories, int type)
{
return factories[type]->createInstance();
}

void main()
{
SimpleBaseClass                                         *simpleInstance     = NULL;
std::map<int,SimpleBaseClass::SimpleBaseClassFactory *>  factories;

factories[1] = &SimpleClass1::myFactory;
factories[2] = &SimpleClass2::myFactory;

simpleInstance = someMethod (factories,1);
if (simpleInstance)
   {
   simpleInstance->setValue (123);
   std::cout << simpleInstance->getValue() << std::endl;
   delete simpleInstance;
   }
else
   {
   std::cout << "Instance creation failed" << std::endl;
   }

simpleInstance = someMethod (factories,2);
if (simpleInstance)
   {
   simpleInstance->setValue (123);
   std::cout << simpleInstance->getValue() << std::endl;
   delete simpleInstance;
   }
else
   {
   std::cout << "Instance creation failed" << std::endl;
   }
}

Очевидный способ сделать это - создать функцию регистрации внутри каждой библиотеки DLL, которая вызывается для построения карты. Мой вопрос: возможно ли, чтобы моя программа автоматически регистрировала фабрики на карте, например. с помощью некоторой техники метапрограммирования, чтобы пользователю не нужно было выполнять эту функцию, которая потенциально могла бы иметь очень длинный список назначений карты? Я хотел бы создать список или скрипт классов dll во время компиляции, а затем выполнить регистрацию из списка во время выполнения.

Большое спасибо за любую помощь.

Ответы [ 2 ]

0 голосов
/ 19 июля 2011

Вы можете легко это сделать, потребовав от каждого такого экспорта DLL две простые функции

void getAvailableComponents(std::list<string> &components);
IComponent *getComponent(const std::string &componentName);

Здесь getComponentFactory может возвращать либо экземпляр класса, содержащий дополнительные функции, либо упрощенную фабрику, которая их создает.То, что делает IComponent, как он себя ведет и как вы работаете с различными типами классов, действительно зависит от вас и какую часть вашей среды вы хотите показать.

Обратите внимание, что для доступа к этим функциям из вашей программы вам потребуетсяпередать их украшенные имена в GetProcAddress ()

0 голосов
/ 19 июля 2011

Я использую конструкторы глобальных объектов для таких регистраций. Будучи связанными с соответствующим компоновщиком C ++, динамические библиотеки вызывают эти конструкторы при инициализации модуля. Деструкторы также полезны - вы можете выполнить отмену регистрации там.

Итак, идея в том, чтобы использовать глобальную карту, содержащую все загруженные фабрики. Заполните его из конструктора некоторого глобального объекта, определенного в каждой библиотеке.

В Visual Studio может потребоваться заставить компоновщик не оптимизировать объект экземпляра с помощью конструктора. Это может быть сделано путем экспорта рассматриваемой глобальной переменной.

...