I've been attempting to get a better understanding of using a Factory Pattern in C++ lately.
I've consulted the following resources:
How to implement the factory method pattern in C++ correctly
https://www.geeksforgeeks.org/design-patterns-set-2-factory-method/
https://sourcemaking.com/design_patterns/factory_method/cpp/1
https://www.codeproject.com/Articles/363338/Factory-Pattern-in-Cplusplus
https://www.bogotobogo.com/DesignPatterns/factorymethod.php
https://gist.github.com/pazdera/1099562
https://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Design_Patterns
Before somebody marks this as "Not a question", I do have some explicit questions which I'll get to in a moment. But to clarify my understanding so far first I'd like to start with an example. This is the best example I've been able to make from the information in the above links (best meaning illustrates the Factory Pattern but is as simple as possible so beginners to this pattern can plainly see the issues involved):
// FactoryPattern.cpp
#include <iostream>
#include <vector>
enum AnimalSpecies { dog, cat };
class Animal
{
public:
virtual void makeSound() = 0;
};
class Dog : public Animal
{
public:
void makeSound() { std::cout << "woof" << "\n\n"; }
};
class Cat : public Animal
{
public:
void makeSound() { std::cout << "meow" << "\n\n"; }
};
class AnimalFactory
{
public:
static Animal* makeAnimal(AnimalSpecies animalSpecies);
};
Animal* AnimalFactory::makeAnimal(AnimalSpecies animalSpecies)
{
if (animalSpecies == AnimalSpecies::dog)
{
return(new Dog());
}
else if (animalSpecies == AnimalSpecies::cat)
{
return(new Cat());
}
else
{
std::cout << "error in AnimalFactory::makeAnimal(), animalSpecies = " << animalSpecies << " does not seem to be valid" << "\n\n";
return(nullptr);
}
}
int main(void)
{
std::vector<Animal*> animals;
animals.push_back(AnimalFactory::makeAnimal(AnimalSpecies::dog));
animals.push_back(AnimalFactory::makeAnimal(AnimalSpecies::cat));
for (auto &animal : animals)
{
animal->makeSound();
}
for (auto& animal : animals)
{
delete(animal);
}
return(0);
}
The output of this program (as intended) is:
woof
meow
Here are my questions at this time:
1) Some of the reading I've done on the Factory Pattern has led me to believe that eliminating if statements is part of the benefit. The above example fails in that regard since in AnimalFactory::makeAnimal()
an if-else
has to be used to determine species. Is there a way to refactor this to remove if statements?
2) With the various changes and improvements in C++ 14/17/20 lately, many of us are moving away from pointers to avoid the possibility of memory leaks. Is there a way to refactor this so as to not use pointers?
3) What is the advantage of the Factory Pattern? i.e. in the above example why not omit class AnimalFactory
and simply make main()
as follows:
int main(void)
{
Dog dog;
dog.makeSound();
Cat cat;
cat.makeSound();
return(0);
}