Intent:
Provide an interface for creating families of related or dependent objects without specifying their concrete classes
Mostly used for encapsulating different context. Context can be OS, database, windowing systems.
//The Herbivore class - The 'AbstractProductA' abstract class
class Herbivore
{
public:
virtual const string& getName(void)=0;
};
//Lets define couple of Herbivores called Cow and Deer
class Cow : public Herbivore //The 'ProductA1' class
{
public:
Cow():name("Cow"){};//default destructor
const string& getName(void)
{return name;}
private:
string name;
};
class Deer : public Herbivore //The 'ProductA2' class
{
public:
Deer():name("Deer"){}; //default destructor
const string& getName(void) {return name;}
private: string name;
};
//The Carnivore class - The 'AbstractProductB' abstract class
class Carnivore
{
public:
virtual const string& getName(void)=0;
virtual void eat(Herbivore& h) = 0;
};
//Lets define couple of Carnivores called Lion and Wolf
class Lion : public Carnivore //The 'ProductB1' class
{
public:
Lion():name("Lion"){};
const string& getName(void) {return name;}
void eat(Herbivore& h) //override
{ cout << name << " eats " << h.getName() << endl; }
private:
string name;
};
class Wolf : public Carnivore //The 'ProductB2' class
{
public:
Wolf():name("Wolf"){};
const string& getName(void) {return name;}
void eat(Herbivore& h) //override
{ cout << name << " eats " << h.getName() << endl; }
private:
string name;
};
//The 'AbstractFactory' abstract class
class ContinentFactory
{
public:
virtual Herbivore& CreateHerbivore() = 0;
virtual Carnivore& CreateCarnivore() = 0;
};
class AfricaFactory : public ContinentFactory//The 'ConcreteFactory1' class
{
Herbivore& CreateHerbivore()
{
return *(dynamic_cast<Herbivore *>(new Cow()));
}
Carnivore& CreateCarnivore()
{
return *(dynamic_cast<Carnivore *>(new Lion()));
}
};
class AmericaFactory : public ContinentFactory //The 'ConcreteFactory2' class
{
Herbivore& CreateHerbivore()
{
return *(dynamic_cast<Herbivore *>(new Deer()));
}
Carnivore& CreateCarnivore()
{
return *(dynamic_cast<Carnivore *>(new Wolf()));
}
};
//The 'Client' class
class AnimalWorld
{
public:
AnimalWorld(ContinentFactory& factory):_herbivore(factory.CreateHerbivore()),
_carnivore(factory.CreateCarnivore())
{ }
void RunFoodChain()
{
_carnivore.eat(_herbivore);
}
private:
Herbivore& _herbivore;
Carnivore& _carnivore;
};
int main()
{
//Create and run African Animal World
ContinentFactory& africa = *(dynamic_cast<ContinentFactory *>(new AfricaFactory()));
AnimalWorld& world1 = *(new AnimalWorld(africa));
world1.RunFoodChain();
// Create and run the American animal world
ContinentFactory& america = *(dynamic_cast<ContinentFactory *>(new AmericaFactory()));
AnimalWorld& world2 = *(new AnimalWorld(america));
world2.RunFoodChain();
return 0;
}
Consequences:
Advantages:
By changing only the factory, the whole family of objects change. It promotes consistency among products because an application can use objects only from one family at a time.
Disadvantages:
New products cannot be supported easily because the AbstractFactory intereface fixes the set of products that can be created. If a new product is to be supported, it would involve changing the AbstractFactory and all its sub classes.
When to use this pattern:
Use abstract factory when
1] A system should be independent of how its products are created, composed and represented.
2] A system should be configured with one of multiple families of products.
3] A system should be able to use classes only from one family at a time and you want to enforce that.
Difference between Factory Method and Abstract Factory Method:
Factory Method | Abstract Factory |
Manages the creation of object without depending on its concrete type. | Manages creation of related families or interdependent classes without depending on their concrete types. |
Sub classes manage the creation of the concrete type | Creation depends on the type of factory used. |
Easy to extend the factory class to support new products. | Difficult to extend the factories to support new products. |
Many factories can be used simultaneously. | Only once factory is used at a time. |