/* 
 * abstract_factory.cpp
 *
 * Example of Abstract Factory Pattern. Provide an interface for creating
 * families of related or dependent objects without specifying their concrete classes.
 */

#include <iostream>

namespace ProductA {

  class Abstract {
  public:
    virtual void action() = 0;
  };

  class Specific1 : public Abstract {
  public:
    virtual void action() { std::cout << "SpecificProduct A1 action.\n"; }
  };

  class Specific2 : public Abstract {
  public:
    virtual void action() { std::cout << "SpecificProduct A2 action.\n"; }
  };

}

namespace ProductB {

  class Abstract {
  public:
    virtual void action() = 0;
  };

  class Specific1 : public Abstract {
  public:
    virtual void action() { std::cout << "SpecificProduct B1 action.\n"; }
  };

  class Specific2 : public Abstract {
  public:
    virtual void action() { std::cout << "SpecificProduct B2 action.\n"; }
  };

}

class AbstractFactory {
public:
  virtual ProductA::Abstract* create_product_A() = 0;
  virtual ProductB::Abstract* create_product_B() = 0;
};

class ConcreteFactory1 : public AbstractFactory {
public:
  virtual ProductA::Specific1* create_product_A() { return new ProductA::Specific1; }
  virtual ProductB::Specific1* create_product_B() { return new ProductB::Specific1; }
};

class ConcreteFactory2 : public AbstractFactory {
public:
  virtual ProductA::Specific2* create_product_A() { return new ProductA::Specific2; }
  virtual ProductB::Specific2* create_product_B() { return new ProductB::Specific2; }
};

class Client {

public:
  Client(AbstractFactory* factory)
    : _factory(factory)
  {
    _productA = factory->create_product_A();
    _productB = factory->create_product_B();
  }

  void dosomething()
  {
    _productA->action();
    _productB->action();
  }

private:
  AbstractFactory*  _factory;
  ProductA::Abstract* _productA;
  ProductB::Abstract* _productB;
};

int main()
{
  AbstractFactory* factory = new ConcreteFactory2;
  Client c(factory);
  c.dosomething();
}

