Порождающий паттерн. Абстрактная фабрика.


Абстрактная фабрика.

Паттерн представляет интерфейс для создания семейств, связанных между собой, или независимых объектов, конкретные классы которых неизвестны.
От класса "абстрактная фабрика" наследуются классы конкретных фабрик, которые содержат методы создания конкретных объектов-продуктов, являющихся наследниками класса "абстрактный продукт", объявляющего интерфейс для их создания. Клиент пользуется только интерфейсами, заданными в классах "абстрактная фабрика" и "абстрактный продукт".
Паттерн изолирует клиента от деталей реализации классов, упрощает замену семейств продуктов и гарантирует их сочетаемость. Паттерн применяется, если:
  • система не должна зависеть от того, как создаются и представляются входящие в нее объекты
  • входящие в семейство взаимосвязанные объекты должны использоваться вместе, и вам необходимо обеспечить выполнение этого ограничения
  • система должна конфигурироваться одним из семейств составляющих ее объектов
  • вы хотите представить библиотеку объектов, раскрывая только их интерфейсы, но не реализацию

Ниже пример абстрактной фабрики, которая настраивает ядро системы на то как рисовать, как отправлять данные по сети, и как хранить настройки системы. В этом примере показано то как создаются абсолютно несвязанные с собой объекты, но которые объеденены в семейство - Ядро Системы
#include <cmath>
#include <iostream>
#include <memory>

// интерфейс для рисования
struct IDrawer
{
  virtual void draw() = 0;
};

// рисуем с помощью OpenGL
struct GLDrawer : IDrawer
{
  void draw() override
  {
    std::cout << "OpenGL draw" << std::endl;
  }
};

// рисуем с помощью DirectX
struct DirectXDrawer : IDrawer
{
  void draw() override
  {
    std::cout << "DirectX draw" << std::endl;
  }
};

// интерфейс для отправки сообщений по сети
struct INetworkSender
{
  virtual void sendData() = 0;
};

// отправка сообщения по проводной сети
struct NetworkWiredSender : INetworkSender
{
  void sendData() override
  {
    std::cout << "sended by Wired" << std::endl;
  }
};

// отправка сообщения с помощью GSM модуля
struct NetworkGSMSender : INetworkSender
{
  void sendData() override
  {
    std::cout << "sended by GSM" << std::endl;
  }
};

// интерфейс для хранения данных в базе
struct IDataBase
{
  virtual void save() = 0;
};

// хранение в локально базе
struct LocalDB : IDataBase
{
  void save()override
  {
    std::cout << "saved on local" << std::endl;
  }
};

// хранение в удаленной базе
struct RemoteDB : IDataBase
{
  void save()override
  {
    std::cout << "saved on remote" << std::endl;
  }
};

// интерфейс фабрики для семейства AppCore
struct IAppCoreFactory
{
  virtual std::unique_ptr<IDrawer>        createDrawer() = 0;
  virtual std::unique_ptr<INetworkSender> createNetwork() = 0;
  virtual std::unique_ptr<IDataBase>      createDataBase() = 0;
};

// фабрика 1 (для платформы с OpenGL, Wired Network, Local DB)
struct AppCorePlatformFactory1 : IAppCoreFactory
{
  std::unique_ptr<IDrawer> createDrawer() override
  {
    return std::make_unique<GLDrawer>();
  }

  std::unique_ptr<INetworkSender> createNetwork() override
  {
    return std::make_unique<NetworkWiredSender>();
  }

  std::unique_ptr<IDataBase> createDataBase() override
  {
    return std::make_unique<LocalDB>();
  }
};

// фабрика 1 (для платформы с DirectX, GSM Network, Remote DB)
struct AppCorePlatformFactory2 : IAppCoreFactory
{
  std::unique_ptr<IDrawer> createDrawer() override
  {
    return std::make_unique<DirectXDrawer>();
  }

  std::unique_ptr<INetworkSender> createNetwork() override
  {
    return std::make_unique<NetworkGSMSender>();
  }

  std::unique_ptr<IDataBase> createDataBase() override
  {
    return std::make_unique<RemoteDB>();
  }
};

// класс ядра нашей системы
struct AppCore
{
  AppCore(std::unique_ptr<IAppCoreFactory> &&apFactory)
  {
    mDrawer  = apFactory->createDrawer();
    mNetwork = apFactory->createNetwork();
    mDB      = apFactory->createDataBase();
  }

  void processing()
  {
    if(mDrawer)  mDrawer->draw();
    if(mNetwork) mNetwork->sendData();
    if(mDB)      mDB->save();
  }

private:
  std::unique_ptr<IDrawer>        mDrawer;
  std::unique_ptr<INetworkSender> mNetwork;
  std::unique_ptr<IDataBase>      mDB;
};

int main()
{
  std::unique_ptr<AppCore> globalCore;

  int variant = 0;
  // загружаем что-то
  // или проверяем на доступность библиотек для:
  // рисования, баз данных, сети

  // ...
  variant = 0;// std::rand() % 2;
  // в зависимости от возможностей, выбираем нужную фабрику
  // которая настраивает наше ядро на определенные библиотеки
  // создавая объекты различных типов
  // которые совершенно не связаны друг с другом
  switch(variant)
  {
    case 0:
    {
      auto factory = std::make_unique<AppCorePlatformFactory1>();
      globalCore   = std::make_unique<AppCore>(std::move(factory));
      break;
    }
    case 1:
    {
      auto factory = std::make_unique<AppCorePlatformFactory2>();
      globalCore   = std::make_unique<AppCore>(std::move(factory));
      break;
    }
  }

  // ...
  globalCore->processing();
  return 0;
}
Фабрики находятся отдельно от классов, интерфейсы классов объектов ядра системы, совершенно не знают друг о друге. Соответственно система получается очень гибкой, есть возможность дописывать различные классы и создавать новые фабрики.


ВОЗМОЖНЫ ДОПОЛНЕНИЯ

Комментарии