An example Abstract Factory design pattern implementation in C++

I’m still working my way through the early stages of the Gang of Four’s Design Patterns: Elements of Reusable Object-Oriented Software, and this time I went to implement an abstract factory. Amazingly, I couldn’t find any fully working decent examples in C++, so I ended up taking the C# code from this dofactory post and converting it.

To be perfectly honest, it took me a while and a not unreasonable amount of swearing to get this up and running – but I guess that’s par for the course when you’re learning new things. Or at least that seems to be the case with me.

The Abstract Factory design pattern itself looks like this:

Abstract Factory UML Class Diagram

While the example code, involving continents, herbivores and carnivores goes like this:

  1. /*
  2. Design Patterns: Elements of Reusable Object-Oriented Software, page 87
  3.  
  4. Applicability:
  5. 	Use the Abstract Factory pattern when:
  6. 		- a system should be independent of how its products are created, composed and represented,
  7. 		- a system should be configured with one of multiple families of products,
  8. 		- a family or related product objects are designed to be used together, and you need to enforce this constraint,
  9. 		- you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations.
  10.  
  11. Consequences:
  12. 	Using the Abstract Factory pattern:
  13. 		- isolates concrete classes,
  14. 		- makes exchanging product families easier,
  15. 		- promotes consistency among products,
  16. 		- BUT supporting new kinds of products is difficult.
  17. */
  18.  
  19. #include <iostream>
  20. #include <string>
  21.  
  22. using namespace std;
  23.  
  24. // The 'AbstractProductA' abstract class. Baseclass for the Wildebeast and Bison classes.
  25. class Herbivore
  26. {
  27. 	private:
  28. 		string animalName;
  29.  
  30. 	public:
  31. 		Herbivore(string theAnimalName)
  32. 		{
  33. 			animalName = theAnimalName;
  34. 		}
  35.  
  36. 		string getName()
  37. 		{
  38. 			return animalName;
  39. 		}
  40. };
  41.  
  42.  
  43. // The 'ProductA1' class
  44. class Wildebeest : public Herbivore
  45. {
  46. 	public:
  47. 		// Empty constructor - construction occurs in the Herbivore constructor.
  48. 		Wildebeest(string theAnimalName) : Herbivore(theAnimalName) {}
  49. };
  50.  
  51.  
  52. // The 'ProductA2' class
  53. class Bison : public Herbivore
  54. {
  55. 	public:
  56. 		// Empty constructor - construction occurs in the Herbivore constructor.
  57. 		Bison(string theAnimalName) : Herbivore(theAnimalName) {}
  58. };
  59.  
  60.  
  61. // The 'AbstractProductB' abstract class. Pure abstract class, and baseclass for the Lion and Wolf classes.
  62. class Carnivore
  63. {
  64. 	private:
  65. 		string animalName;
  66.  
  67. 	public:
  68. 		Carnivore(string theAnimalName)
  69. 		{
  70. 			animalName = theAnimalName;
  71. 		}
  72.  
  73. 		// Having a pure virtual function like this makes the Carnivore class an abstract class which
  74. 		// cannot be instantiated, but you can legally create a pointer to one (which we do).
  75. 		virtual void eat(Herbivore h) = 0;
  76.  
  77. 		string getName()
  78. 		{
  79. 			return animalName;
  80. 		}
  81. };
  82.  
  83.  
  84. // The 'ProductB1' class
  85. class Lion : public Carnivore
  86. {
  87.  
  88. 	public:
  89. 		// Empty constructor - construction occurs in the Carnivore constructor
  90. 		Lion(string theAnimalName) : Carnivore(theAnimalName) {}
  91.  
  92. 		virtual void eat(Herbivore h)
  93. 		{
  94. 			// Eat Wildebeast
  95. 			cout << this->getName() << " eats " << h.getName() << endl;
  96. 		}
  97. };
  98.  
  99.  
  100. // The 'ProductB2' class
  101. class Wolf : public Carnivore
  102. {
  103. 	public:
  104. 		// Empty constructor - construction occurs in the Carnivore constructor
  105. 		Wolf(string theAnimalName) : Carnivore(theAnimalName) {}
  106.  
  107. 		virtual void eat(Herbivore h)
  108. 		{
  109. 			// Eat Bison
  110. 			cout << this->getName() << " eats " + h.getName() << endl;
  111. 		}
  112. };
  113.  
  114.  
  115. // The 'AbstractFactory' abstract class. Pure abstract class - cannot be instantiated, but again we can create pointers to one.
  116. class ContinentFactory
  117. {
  118. 	public:
  119. 		virtual Herbivore* CreateHerbivore() = 0;
  120. 		virtual Carnivore* CreateCarnivore() = 0;
  121. };
  122.  
  123.  
  124. // The 'ConcreteFactory1' class
  125. class AfricaFactory : public ContinentFactory
  126. {
  127. 	public:
  128. 		virtual Herbivore* CreateHerbivore()
  129. 		{
  130. 			return new Wildebeest("William Wildebeest");
  131. 		}
  132.  
  133. 		virtual Carnivore* CreateCarnivore()
  134. 		{
  135. 			return new Lion("Lenny Lion");
  136. 		}
  137. };
  138.  
  139.  
  140. // The 'ConcreteFactory2' class
  141. class AmericaFactory : public ContinentFactory
  142. {
  143. 	virtual Herbivore* CreateHerbivore()
  144. 	{
  145. 		return new Bison("Bob Bison");
  146. 	}
  147.  
  148. 	virtual Carnivore* CreateCarnivore()
  149. 	{
  150. 		return new Wolf("Walter Wolf");
  151. 	}
  152. };
  153.  
  154.  
  155. // The 'Client' class. This class calls the factory classes to create animals of the relevant type.
  156. class AnimalWorld
  157. {
  158. 	private:
  159. 		Herbivore* mHerbivore;
  160. 		Carnivore* mCarnivore;
  161.  
  162. 	public:
  163. 		// Constructor. Creates a suitable pair of herbivores and carnivores for the continent.
  164. 		AnimalWorld(ContinentFactory *pFactory)
  165. 		{
  166. 			mHerbivore = pFactory->CreateHerbivore();
  167. 			mCarnivore = pFactory->CreateCarnivore();
  168. 		}
  169.  
  170. 		void runFoodChain()
  171. 		{
  172. 			mCarnivore->eat(*mHerbivore);
  173. 		}
  174. };
  175.  
  176.  
  177. // Let the carnage begin...
  178. int main()
  179. {
  180. 	// Create and run the African animal world
  181. 	ContinentFactory *pAfrica = new AfricaFactory;
  182. 	AnimalWorld *pWorld = new AnimalWorld(pAfrica);
  183. 	pWorld->runFoodChain();
  184.  
  185. 	// Create and run the American animal world
  186. 	ContinentFactory *pAmerica = new AmericaFactory;
  187. 	pWorld = new AnimalWorld(pAmerica);
  188. 	pWorld->runFoodChain();
  189.  
  190. 	return 0;
  191. }

That’s a lot of work to get the output:

Lenny Lion eats William Wildebeest
Walter Wolf eats Bob Bison

But the point isn’t the output, it’s the structure of the classes and how it does what it does. Now I just have to learn when and how to apply the pattern to problems not involving imaginary animals… =D

2 thoughts on “An example Abstract Factory design pattern implementation in C++”

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.