The Factory Pattern is a design technique frequently applied in object-oriented programming to instantiate objects while concealing the creation process from the client. Essentially, this pattern defines a method for generating objects within a parent class, enabling child classes to customize the specific type of objects generated.
C++ serves as a programming language focused on object-oriented principles and facilitates the Factory Pattern through the utilization of polymorphism and abstract classes. In order to apply the Factory Pattern within C++, the initial step involves establishing an abstract base class that outlines the shared interface for all objects producible by the factory. This foundational abstract base class is commonly referred to as the "Product" interface.
Explanation
Let's consider a demonstration of a basic program that generates various kinds of creatures. We can establish our abstract base class "Animal" in the following manner:
class Animal {
public:
virtual void makeSound() = 0;
virtual ~Animal() {}
};
The "Animal" class serves as an abstract base class, establishing a shared interface for various animal types. This interface primarily revolves around a singular method named "makeSound". This method is designated as pure virtual, indicating that it lacks an implementation in the base class and necessitates implementation by its derived classes. Additionally, the destructor is virtual, guaranteeing proper destruction of derived class objects when deleted through a base class pointer.
Next, we have the option to generate various animal variations by developing concrete classes that adhere to the "Animal" interface. To illustrate, we will design two concrete classes: "Cat" and "Dog":
class Cat : public Animal {
public:
void makeSound() {
std::cout << "Meow!" << std::endl;
}
};
class Dog : public Animal {
public:
void makeSound() {
std::cout << "Woof!" << std::endl;
}
};
Both the classes "Cat" and "Dog" are derived from the "Animal" class and define the "makeSound" function.
Now, we are able to establish our factory class, which holds the responsibility of generating instances of the "Animal" category. This factory class must possess the capability to construct instances of any category that is derived from the "Animal" class.
class AnimalFactory {
public:
virtual Animal* createAnimal() = 0;
virtual ~AnimalFactory() {}
};
The base class "AnimalFactory" serves as an abstract class outlining the structure for generating instances of the "Animal" class. This structure includes a solitary function named "createAnimal" that yields a reference to an "Animal" instance. The function is defined as a pure virtual method, signifying that it lacks an implementation in the base class and necessitates implementation in its derived classes.
Now, we have the ability to develop specific factory classes that adhere to the "AnimalFactory" interface and produce instances of various animal types. For instance, we will establish two distinct factory classes: "CatFactory" and "DogFactory":
class CatFactory : public AnimalFactory {
public:
Animal* createAnimal() {
return new Cat();
}
};
class DogFactory : public AnimalFactory {
public:
Animal* createAnimal() {
return new Dog();
}
};
Both the classes "CatFactory" and "DogFactory" are derived from the base class "AnimalFactory" and define the "createAnimal" function. This function is responsible for instantiating a new object of the corresponding type ("Cat" or "Dog") and then providing a pointer to the base class "Animal".
The complete code is:
#include <iostream>
class Animal {
public:
virtual void makeSound() = 0;
virtual ~Animal() {}
};
class Cat : public Animal {
public:
void makeSound() {
std::cout << "Meow!" << std::endl;
}
};
class Dog : public Animal {
public:
void makeSound() {
std::cout << "Woof!" << std::endl;
}
};
class AnimalFactory {
public:
virtual Animal* createAnimal() = 0;
virtual ~AnimalFactory() {}
};
class CatFactory : public AnimalFactory {
public:
Animal* createAnimal() {
return new Cat();
}
};
class DogFactory : public AnimalFactory {
public:
Animal* createAnimal() {
return new Dog();
}
};
class AnimalClient {
public:
AnimalClient(AnimalFactory* factory) {
animal_ = factory->createAnimal();
}
void makeAnimalSound() {
animal_->makeSound();
}
~AnimalClient() {
delete animal_;
}
private:
Animal* animal_;
};
int main() {
AnimalFactory* catFactory = new CatFactory();
AnimalClient* catClient = new AnimalClient(catFactory);
catClient->makeAnimalSound();
delete catClient;
delete catFactory;
AnimalFactory* dogFactory = new DogFactory();
AnimalClient* dogClient = new AnimalClient(dogFactory);
dogClient->makeAnimalSound();
delete dogClient;
delete dogFactory;
return 0;
}
Output:
Conclusion
Finally, we can employ the factory design pattern to generate instances of various animal types without requiring knowledge of the specific object implementations. A client class can be developed to utilize the factory for creating instances of the "Animal" class.