Wednesday 28 July 2010

C++ example for Abstract Factory Design Pattern

The Abstract Factory Design Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. The following UML class diagram explains how the Abstract Factory fits with the rest.


The following is example of Abstract factory design pattern:



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Abstract Factory is part of Creational Patterns
//Creational Patterns deal with initializing and configuring classes and objects
//Abstract Factory creates an instance of several families of classes

//We will take an example of Animal Classes and Abstract them.
//There are 2 types of animals; Herbivores and Carnivores.
//The rule of nature is that Carnivores eats Herbivores which will be shown
//Different animas live in different continents but the same rule applies

#include<iostream>
#include<string>

using namespace
std;

//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;
}





The output is as follows:



For more details please see: http://www.dofactory.com/Patterns/PatternAbstract.aspx

8 comments:

  1. It really helped me to understand thanks, I searched a lot on net to find simple and illustrative c++ factory example!

    ReplyDelete
  2. AnimalWorld(ContinentFactory& factory):_herbivore(factory.CreateHerbivore()),_carnivore(factory.CreateCarnivore()) gets cut off, perhaps make one line.

    ReplyDelete
  3. Arun B Krishna.
    Simple & Clear exapmle. Would be great if able to relate to the theoretical concepts like what is the exact advantage we are achieving here compared to the normal implementation.

    ReplyDelete
  4. Hi..can u pls explain this
    AnimalWorld(ContinentFactory& factory):_herbivore(factory.CreateHerbivore()),_carnivore(factory.CreateCarnivore())

    ReplyDelete
  5. Why you have used dynamic cast.
    Herbivore& CreateHerbivore()
    {
    return *(dynamic_cast(new Deer()));
    }

    Upcasting is inhernt, I think there is no need to use dynamic cast.I think below code will do the needful task.Correct me if I'm wrong.

    Herbivore& CreateHerbivore()
    {
    return *(new Deer());
    }

    ReplyDelete
  6. @Anonymous(Sep8.....)
    See what this does is..AnimalWorld accepts a ref to the ContinentFactory,which can be of anytype (any continent: africa, america)...as those continent have implemented the Abstract ContinentFactory class.
    Now as it can take any type so with that type he is creating the products, in this case herbivore and carnivore animals.
    As in the main if you see..first the user has passed africa continent ref...
    ContinentFactory& africa = *(dynamic_cast(new AfricaFactory()));
    As you can see new AfricaFactory(), africa is pointing to AfricaFactory here...and the client class
    AnimalWorld is initialized with this continent now...
    AnimalWorld& world1 = *(new AnimalWorld(africa));
    Now as the continent is clear to this animalworld he will call createherbivore and createcarnivore of africa continent, which says herbivore is cow and carnivore is lion.
    And then in main Runfoodchain() is called of animalworld which knows who is who...
    So first it printed Lion eats cow.
    I hope this helps you in understanding this pattern and clear your doubts too.
    AnimalWorld& world1 = *(new AnimalWorld(africa));

    ReplyDelete