Как создать простую фабрику объектов C++?

В моем приложении 10-20 классов создаются один раз [*]. Вот пример:

class SomeOtherManager;

class SomeManagerClass {
public:
    SomeManagerClass(SomeOtherManager*);
    virtual void someMethod1();
    virtual void someMethod2();
};

Экземпляры классов содержатся в одном объекте:

class TheManager {
public:
    virtual SomeManagerClass* someManagerClass() const;
    virtual SomeOtherManager* someOtherManager() const;
    /** More objects... up to 10-20 */
};

В настоящее время TheManager использует оператор новый для создания объектов.

Я намерен заменить, используя плагины, реализацию SomeManagerClass (или любого другого класса) на другую. Для того, чтобы заменить реализацию, нужно 2 шага:

  1. Определите класс DerivedSomeManagerClass, который наследует SomeManagerClass [плагин]
  2. Создайте новый класс (DerivedSomeManagerClass) вместо класса по умолчанию (SomeManagerClass) [приложение]

Думаю, мне нужна какая-то фабрика объектов, но она должна быть довольно простой, поскольку всегда нужно создать только один тип (реализация по умолчанию или реализация пользователя).

Есть идеи, как спроектировать простую фабрику, как я только что описал? Учтите тот факт, что в будущем может быть больше классов, поэтому его будет легко расширять.

[*] Меня не волнует, случится ли это более одного раза.

Редактировать: Обратите внимание, что в TheManager содержится более двух объектов.

Вы хотите заменить экземпляры SomeManagerClass во время выполнения или во время разработки?

Joris Timmermans 02.12.2008 12:51

SomeManagerClass создается только один раз - при запуске приложения, поэтому я хочу изменить это создание. Однако это должно быть во время выполнения, поскольку код, заменяющий реализацию по умолчанию, находится в динамически связанном подключаемом модуле.

kshahar 02.12.2008 12:56

FWIW, я думаю, что всякий раз, когда вы называете класс «Менеджер», это происходит потому, что вы не знаете, что он на самом деле делает. Вы также можете называть это «ящиком» или «вещью». Имя - запах, имхо.

metao 13.02.2009 12:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
3
26 682
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Вы можете реализовать объектную фабрику с помощью статических методов, которые возвращают экземпляр класса-менеджера. На фабрике вы можете создать метод для типа менеджера по умолчанию и метод для любого типа менеджера, который вы даете аргумент, представляющий тип класса менеджера (скажем, с перечислением). Этот последний метод должен возвращать интерфейс, а не класс.

Обновлено: я попытаюсь дать некоторый код, но помните, что мои времена C++ довольно давно, и я пока делаю только Java и некоторые сценарии.

class Manager { // aka Interface
    public: virtual void someMethod() = 0;
};

class Manager1 : public Manager {
    void someMethod() { return null; }
};

class Manager2 : public Manager {
    void someMethod() { return null; }
};

enum ManagerTypes {
    Manager1, Manager2
};

class ManagerFactory {
    public static Manager* createManager(ManagerTypes type) {
        Manager* result = null;
        switch (type) {
        case Manager1:
             result = new Manager1();
             break;
        case Manager2:
             result = new Manager2();
             break;
        default:
             // Do whatever error logging you want
             break;
        }
        return result;
     }
 };

Теперь у вас должна быть возможность вызвать Factory через (если вы смогли заставить образец кода работать):

Manager* manager = ManagerFactory.createManager(ManagerTypes.Manager1);

Спасибо за код. В своем вопросе я имел в виду, что хочу заменить «new Manager2 ();» операторы с созданием производных классов.

kshahar 02.12.2008 13:45

Я не понимаю, извините. Вы можете расширить перечисление и фабрику, чтобы наследовать другие классы.

boutta 02.12.2008 15:37

Вот решение, которое я придумал, оно не лучшее, но, возможно, поможет придумать лучшие решения:

Для каждого класса будет свой класс-создатель:

class SomeManagerClassCreator {
public:
    virtual SomeManagerClass* create(SomeOtherManager* someOtherManager) { 
        return new SomeManagerClass(someOtherManager); 
    }
};

Тогда создатели соберутся в один класс:

class SomeManagerClassCreator;
class SomeOtherManagerCreator;

class TheCreator {
public:
    void setSomeManagerClassCreator(SomeManagerClassCreator*);
    SomeManagerClassCreator* someManagerClassCreator() const;

    void setSomeOtherManagerCreator(SomeOtherManagerCreator*);
    SomeOtherManagerCreator* someOtherManagerCreator() const;
private:
    SomeManagerClassCreator* m_someManagerClassCreator;
    SomeOtherManagerCreator* m_someOtherManagerCreator;
};

И TheManager будет создан с TheCreator для внутреннего создания:

class TheManager {
public:
    TheManager(TheCreator*);
    /* Rest of code from above */
};

Проблема с этим решением заключается в том, что оно нарушает DRY - для каждого создателя класса мне пришлось бы написать сеттер / получатель в TheCreator.

Я не понимаю на сто процентов, и мне не очень нравятся фабричные штучки из книг и статей.


Если у всех ваших менеджеров одинаковый интерфейс, вы можете унаследовать его от базового класса и использовать этот базовый класс в своей программе. В зависимости от того, где будет принято решение о том, какой класс будет создан, вы должны использовать идентификатор для создания (как указано выше) или обрабатывать решение, какой менеджер создать внутри.


Другой способ - реализовать его «политику», например, с помощью шаблонов. Так что You ManagerClass :: create () возвращает конкретный экземпляр SomeOtherManagerWhatever. Это заложило бы решение о том, какой менеджер принять в коде, который использует ваш менеджер - Мэй это не предназначено.

Или так:


template<class MemoryManagment>
class MyAwesomeClass
{
    MemoryManagment m_memoryManager;
};

(или что-то вроде того) С помощью этой конструкции вы можете легко использовать другие менеджеры, изменяя только экземпляр MyAwesomeClass.


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

Я бы создал «базовую» фабрику, у которой есть виртуальные методы для создания всех основных менеджеров, и позволил бы «мета-менеджеру» (TheManager в вашем вопросе) принимать указатель на базовую фабрику в качестве параметра конструктора.

Я предполагаю, что «фабрика» может настраивать экземпляры CXYZWManager, производя их от них, но в качестве альтернативы конструктор CXYZWManager может принимать разные аргументы в «настраиваемой» фабрике.

Пример длинного кода, который выводит CSomeManager и CDerivedFromSomeManager:

#include <iostream>
//--------------------------------------------------------------------------------
class CSomeManager
  {
  public:
    virtual const char * ShoutOut() { return "CSomeManager";}
  };

//--------------------------------------------------------------------------------
class COtherManager
  {
  };

//--------------------------------------------------------------------------------
class TheManagerFactory
  {
  public:
    // Non-static, non-const to allow polymorphism-abuse
    virtual CSomeManager   *CreateSomeManager() { return new CSomeManager(); }
    virtual COtherManager  *CreateOtherManager() { return new COtherManager(); }
  };

//--------------------------------------------------------------------------------
class CDerivedFromSomeManager : public CSomeManager
  {
  public:
    virtual const char * ShoutOut() { return "CDerivedFromSomeManager";}
  };

//--------------------------------------------------------------------------------
class TheCustomManagerFactory : public TheManagerFactory
  {
  public:
    virtual CDerivedFromSomeManager        *CreateSomeManager() { return new CDerivedFromSomeManager(); }

  };

//--------------------------------------------------------------------------------
class CMetaManager
  {
  public:
    CMetaManager(TheManagerFactory *ip_factory)
      : mp_some_manager(ip_factory->CreateSomeManager()),
        mp_other_manager(ip_factory->CreateOtherManager())
      {}

    CSomeManager  *GetSomeManager()  { return mp_some_manager; }
    COtherManager *GetOtherManager() { return mp_other_manager; }

  private:
    CSomeManager  *mp_some_manager;
    COtherManager *mp_other_manager;
  };

//--------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
  {
  TheManagerFactory standard_factory;
  TheCustomManagerFactory custom_factory;

  CMetaManager meta_manager_1(&standard_factory);
  CMetaManager meta_manager_2(&custom_factory);

  std::cout << meta_manager_1.GetSomeManager()->ShoutOut() << "\n";
  std::cout << meta_manager_2.GetSomeManager()->ShoutOut() << "\n";
  return 0;
  }

Мне нравится это решение, но рассмотрим случай, когда TheManagerFactory необходимо вернуть 20 разных классов. Это означает, что он должен знать (используя оператор #include) все 20 классов.

kshahar 02.12.2008 13:43

Базовый фабричный класс может напрямую объявлять все типы менеджеров в заголовке (без зависимостей), и хотя cpp будет включать всех менеджеров, его нужно будет построить только один раз (или несколько раз). Настраиваемым фабрикам нужно только # включить тех менеджеров, которые они переопределяют.

Joris Timmermans 02.12.2008 13:48

Я бы использовал такие шаблоны, потому что не вижу смысла классов фабрик:

class SomeOtherManager;

class SomeManagerClass {
public:
    SomeManagerClass(SomeOtherManager*);
    virtual void someMethod1();
    virtual void someMethod2();
};


class TheBaseManager {
public:
      // 
};

template <class ManagerClassOne, class ManagerClassOther> 
class SpecialManager : public TheBaseManager {
    public:
        virtual ManagerClassOne* someManagerClass() const;
        virtual ManagerClassOther* someOtherManager() const;
};

TheBaseManager* ourManager = new SpecialManager<SomeManagerClass,SomeOtherManager>;

Если вы планируете поддерживать подключаемые модули, которые динамически связаны, ваша программа должна будет предоставить стабильный ABI (двоичный интерфейс приложения), это означает, что вы не можете использовать C++ в качестве основного интерфейса, поскольку C++ не имеет стандартного ABI.

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

Вы не можете предоставить динамическую библиотеку, которая позволит вам «создать» класс плагина как есть. Вот почему вам необходимо стандартизировать интерфейс C, чтобы создать объект. Тогда использование объекта C++ возможно, если ни один из ваших аргументов не использует возможно несовместимые типы, например контейнеры STL. Вы не сможете использовать вектор, возвращаемый другой библиотекой, потому что вы не можете гарантировать, что их реализация STL такая же, как ваша.

Manager.h

class Manager
{
public:
  virtual void doSomething() = 0;
  virtual int doSomethingElse() = 0;
}

extern "C" {
Manager* newManager();
void deleteManager(Manager*);
}

PluginManager.h

#include "Manager.h"

class PluginManager : public Manager
{
public:
  PluginManager();
  virtual ~PluginManager();

public:
  virtual void doSomething();
  virtual int doSomethingElse();
}

PluginManager.cpp

#include "PluginManager.h"

Manager* newManager()
{
  return new PluginManager();
}
void deleteManager(Manager* pManager)
{
  delete pManager;
}

PluginManager::PluginManager()
{
  // ...
}

PluginManager::~PluginManager()
{
  // ...
}

void PluginManager::doSomething()
{
  // ...
}

int PluginManager::doSomethingElse()
{
  // ...
}

Я ответил на другой вопрос SO о фабриках C++. Если вас интересует гибкая фабрика, см. там. Я пытаюсь описать старый способ использования макросов из ET ++, который мне очень понравился.

ET ++ был проектом по переносу старого MacApp на C++ и X11. В результате Эрик Гамма и другие начали думать о Шаблоны проектирования.

Вы не говорили о TheManager. Похоже, вы хотите, чтобы это контролировало, какой класс используется? или, может быть, вы пытаетесь связать их вместе?

Похоже, вам нужен абстрактный базовый класс и указатель на текущий используемый класс. Если вы хотите создать цепочку, вы можете сделать это как в абстрактном классе, так и в классе диспетчера. Если абстрактный класс, добавьте члена к следующему классу в цепочке, если менеджер, то отсортируйте его, чтобы использовать в списке. Вам понадобится способ добавления классов, поэтому вам понадобится addMe () в диспетчере. Похоже, вы знаете, что делаете, поэтому, если вы выберете, должно быть правильно. Я рекомендую список с функцией addMe, и если вам нужен только 1 активный класс, тогда функция в TheManager решит, что это было бы хорошо.

Предполагая, что класс (plugin1) наследуется от SomeManagerClass, вам понадобится иерархия классов для создания ваших типов:

class factory
{
public:
    virtual SomeManagerClass* create() = 0;
};

class plugin1_factory : public factory
{
public:
    SomeManagerClass* create() { return new plugin1(); }
};

Затем вы можете назначить эти фабрики на std :: map, где они привязаны к строкам

std::map<string, factory*>  factory_map;
...
factory_map["plugin1"] = new plugin1_factory();

Наконец, вашему TheManager просто нужно знать имя плагина (в виде строки) и он может возвращать объект типа SomeManagerClass всего с одной строкой кода:

SomeManagerClass* obj = factory_map[plugin_name]->create();

РЕДАКТИРОВАТЬ: если вам не нравится иметь один фабричный класс плагина для каждого плагина, вы можете изменить предыдущий шаблон следующим образом:

template <class plugin_type>
class plugin_factory : public factory
{
public:
   SomeManagerClass* create() { return new plugin_type(); }
};

factory_map["plugin1"] = new plugin_factory<plugin1>();

Думаю, это гораздо лучшее решение. Более того, класс plugin_factory может добавить себя в factory_map, если вы передадите costructor строку.

Ответ принят как подходящий

Я думаю, здесь есть две отдельные проблемы.

Одна проблема: как TheManager имя создает класс? Он должен содержать какой-то указатель на «способ создания класса». Возможные решения:

  • сохранение отдельного указателя для каждого типа класса с возможностью его установки, но вы уже сказали, что вам это не нравится, поскольку это нарушает принцип DRY
  • ведение какой-то таблицы, в которой ключом является перечисление или строка; в этом случае установщик - это единственная функция с параметрами (конечно, если ключ является перечислением, вы можете использовать вектор вместо карты)

Другая проблема: что это за «способ создания класса»? К сожалению, мы не можем хранить указатели на конструкторы напрямую, но можем:

  • создать, как указывали другие, фабрику для каждого класса
  • просто добавьте статическую функцию «create» для каждого класса; если они сохраняют последовательную подпись, вы можете просто использовать их указатели на функции

Шаблоны могут помочь избежать ненужного дублирования кода в обоих случаях.

Этот ответ заставил меня переосмыслить различные возможности дизайна и реализации. Это также полезно в качестве руководства к другим ответам, поэтому оно получает награду. Хочу поблагодарить всех за участие, у меня не хватает персонажей, чтобы всех вас благодарить :)

kshahar 15.02.2009 10:45

@UncleZeiv Спустя столько лет я все еще ненавижу тебя за «кражу» моего значка: P

Emiliano 06.12.2017 12:39

@ Эмилиано, ты имеешь в виду награду :) и я даже проголосовал за тебя! <3

UncleZeiv 06.12.2017 15:33

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

Я бы разбил его на 3 раздела.

1) Класс FrameWork будет владеть плагинами. Этот класс отвечает за публикацию интерфейсов, предоставляемых плагинами.

2) Класс PlugIn будет владеть компонентами, выполняющими работу. Этот класс отвечает за регистрацию экспортируемых интерфейсов и привязку импортированных интерфейсов к компонентам.

3) Третий раздел, компоненты - это поставщики и потребители интерфейсов.

Чтобы сделать вещи расширяемыми, подготовка к работе может быть разбита на этапы.

  1. Создавай все.
  2. Подключите все провода.
  3. Начни все.

Чтобы разбить вещи.

  1. Останови все.
  2. Уничтожить все.
class IFrameWork {
public:
    virtual ~IFrameWork() {}
    virtual void RegisterInterface( const char*, void* ) = 0;
    virtual void* GetInterface( const char* name ) = 0;
};

class IPlugIn {
public:
    virtual ~IPlugIn() {}
    virtual void BindInterfaces( IFrameWork* frameWork ) {};
    virtual void Start() {};
    virtual void Stop() {};
};

struct SamplePlugin :public IPlugIn {
    ILogger* logger;

    Component1 component1;
    WebServer  webServer;

public:
    SamplePlugin( IFrameWork* frameWork ) 
        :logger( (ILogger*)frameWork->GetInterface( "ILogger" ) ),  //assumes the 'System' plugin exposes this
        component1(),
        webServer( component1 )
    {
        logger->Log( "MyPlugin Ctor()" );

        frameWork->RegisterInterface( "ICustomerManager", dynamic_cast( &component1 ) ); 
        frameWork->RegisterInterface( "IVendorManager", dynamic_cast( &component1 ) ); 
        frameWork->RegisterInterface( "IAccountingManager", dynamic_cast( &webServer ) ); 
    }

    virtual void BindInterfaces( IFrameWork* frameWork ) {
        logger->Log( "MyPlugin BindInterfaces()" );

        IProductManager* productManager( static_cast( frameWork->GetInterface( "IProductManager" ) ) );
        IShippingManager* shippingManager( static_cast( frameWork->GetInterface( "IShippingManager" ) ) );

        component1.BindInterfaces( logger, productManager );
        webServer.BindInterfaces( logger, productManager, shippingManager );
    }

    virtual void Start() {
        logger->Log( "MyPlugin Start()" );

        webServer.Start();
    }

    virtual void Stop() {
        logger->Log( "MyPlugin Stop()" );

        webServer.Stop();
    }
};

class FrameWork :public IFrameWork {
    vector plugIns;
    map interfaces;
public:
    virtual void RegisterInterface( const char* name, void* itfc ) {
        interfaces[ name ] = itfc;
    }
    virtual void* GetInterface( const char* name )  {
        return interfaces[ name ];
    }

    FrameWork() {
        //Only interfaces in 'SystemPlugin' can be used by all methods of the other plugins
        plugIns.push_back( new SystemPlugin( this ) );

        plugIns.push_back( new SamplePlugin( this ) ); 
        //add other plugIns here

        for_each( plugIns.begin(), plugIns.end(), bind2nd( mem_fun( &IPlugIn::BindInterfaces ), this ) );
        for_each( plugIns.begin(), plugIns.end(), mem_fun( &IPlugIn::Start ) );
    }

    ~FrameWork() {
        for_each( plugIns.rbegin(), plugIns.rend(), mem_fun( &IPlugIn::Stop ) );
        for_each( plugIns.rbegin(), plugIns.rend(), Delete() );
    }
};

Вот минимальная реализация фабричного шаблона, которую я придумал примерно за 15 минут. Мы используем аналогичный, который использует более продвинутые базовые классы.

#include "stdafx.h"
#include <map>
#include <string>

class BaseClass
{
public:
    virtual ~BaseClass() { }
    virtual void Test() = 0;
};

class DerivedClass1 : public BaseClass 
{ 
public:
    virtual void Test() { } // You can put a breakpoint here to test.
};

class DerivedClass2 : public BaseClass 
{ 
public:
    virtual void Test() { } // You can put a breakpoint here to test.
};

class IFactory
{
public:
    virtual BaseClass* CreateNew() const = 0;
};

template <typename T>
class Factory : public IFactory
{
public:
    T* CreateNew() const { return new T(); }
};

class FactorySystem
{
private:
    typedef std::map<std::wstring, IFactory*> FactoryMap;
    FactoryMap m_factories;

public:
    ~FactorySystem()
    {
        FactoryMap::const_iterator map_item = m_factories.begin();
        for (; map_item != m_factories.end(); ++map_item) delete map_item->second;
        m_factories.clear();
    }

    template <typename T>
    void AddFactory(const std::wstring& name)
    {
        delete m_factories[name]; // Delete previous one, if it exists.
        m_factories[name] = new Factory<T>();
    }

    BaseClass* CreateNew(const std::wstring& name) const
    {
        FactoryMap::const_iterator found = m_factories.find(name);
        if (found != m_factories.end())
            return found->second->CreateNew();
        else
            return NULL; // or throw an exception, depending on how you want to handle it.
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    FactorySystem system;
    system.AddFactory<DerivedClass1>(L"derived1");
    system.AddFactory<DerivedClass2>(L"derived2");

    BaseClass* b1 = system.CreateNew(L"derived1");
    b1->Test();
    delete b1;
    BaseClass* b2 = system.CreateNew(L"derived2");
    b2->Test();
    delete b2;

    return 0;
}

Просто скопируйте и вставьте исходное консольное приложение Win32 в VS2005 / 2008. Мне нравится что-то указывать:

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

Похоже, что с шаблонами функций было бы намного проще, чем с шаблоном абстрактной фабрики.

class ManagerFactory
{
public:
    template <typename T> static BaseManager * getManager() { return new T();}
};

BaseManager * manager1 = ManagerFactory::template getManager<DerivedManager1>();

Если вы хотите получить их через строку, вы можете создать стандартную карту из строк в указатели на функции. Вот работающая реализация:

#include <map>
#include <string>

class BaseManager
{
public:
    virtual void doSomething() = 0;
};

class DerivedManager1 : public BaseManager
{
public:
    virtual void doSomething() {};
};

class DerivedManager2 : public BaseManager
{
public:
    virtual void doSomething() {};
};

class ManagerFactory
{
public:
    typedef BaseManager * (*GetFunction)();
    typedef std::map<std::wstring, GetFunction> ManagerFunctionMap;
private:
    static ManagerFunctionMap _managers;

public:
    template <typename T> static BaseManager * getManager() { return new T();}
    template <typename T> static void registerManager(const std::wstring& name)
    {
        _managers[name] = ManagerFactory::template getManager<T>;
    }
    static BaseManager * getManagerByName(const std::wstring& name)
    {
        if (_managers.count(name))
        {
            return _managers[name]();
        }
        return NULL;
    }
};
// the static map needs to be initialized outside the class
ManagerFactory::ManagerFunctionMap ManagerFactory::_managers;


int _tmain(int argc, _TCHAR* argv[])
{
    // you can get with the templated function
    BaseManager * manager1 = ManagerFactory::template getManager<DerivedManager1>();
    manager1->doSomething();
    // or by registering with a string
    ManagerFactory::template registerManager<DerivedManager1>(L"Derived1");
    ManagerFactory::template registerManager<DerivedManager2>(L"Derived2");
    // and getting them
    BaseManager * manager2 = ManagerFactory::getManagerByName(L"Derived2");
    manager2->doSomething();
    BaseManager * manager3 = ManagerFactory::getManagerByName(L"Derived1");
    manager3->doSomething();
    return 0;
}

РЕДАКТИРОВАТЬ: Читая другие ответы, я понял, что это очень похоже на решение FactorySystem Дэйва Ван ден Эйнде, но я использую указатель шаблона функции вместо создания экземпляров шаблонных классов factory. Я думаю, что мое решение немного легче. Из-за статических функций единственный объект, который создается, - это сама карта. Если вам нужна фабрика для выполнения других функций (DestroyManager и т. д.), Я думаю, что его решение более расширяемое.

Вам следует взглянуть на руководство по адресу http://downloads.sourceforge.net/papafactory/PapaFactory20080622.pdf?use_mirror=fastbull

Он содержит отличное руководство по реализации абстрактной фабрики на C++, и исходный код, который поставляется с ним, также очень надежен.

Крис

Другие вопросы по теме