Welcome back! You’ve already explored the power of the Factory Method Pattern and how it promotes flexibility in your code design. Today, we are moving a step further by diving into the Abstract Factory Pattern. This pattern will help you create families of related objects without specifying their concrete classes.
In this lesson, you'll focus on understanding and implementing the Abstract Factory Pattern in C++
. Here's what we’ll cover:
Let's take a look at a part of an example to get a better understanding:
Button.hpp
file to define the abstract Button class and its concrete implementations:
C++1#include <iostream> 2 3// Abstract Product 1: Button as an interface 4class Button { 5public: 6 virtual void paint() = 0; 7 virtual ~Button() = default; 8}; 9 10// Concrete Product WinButton that implements Button with custom 'paint' logic 11class WinButton : public Button { 12public: 13 void paint() override { 14 std::cout << "Rendering a button in a Windows style." << std::endl; 15 } 16}; 17 18// Concrete Product MacButton that implements Button with custom 'paint' logic 19class MacButton : public Button { 20public: 21 void paint() override { 22 std::cout << "Rendering a button in a Mac style." << std::endl; 23 } 24};
Checkbox.hpp
file to define the abstract Checkbox class and its concrete implementations:
C++1// Abstract Product 2: Checkbox as an interface 2class Checkbox { 3public: 4 virtual void paint() = 0; 5 virtual ~Checkbox() = default; 6}; 7 8// Concrete Product WinCheckbox that implements Checkbox with custom 'paint' logic 9class WinCheckbox : public Checkbox { 10public: 11 void paint() override { 12 std::cout << "Rendering a checkbox in a Windows style." << std::endl; 13 } 14}; 15 16// Concrete Product MacCheckbox that implements Checkbox with custom 'paint' logic 17class MacCheckbox : public Checkbox { 18public: 19 void paint() override { 20 std::cout << "Rendering a checkbox in a Mac style." << std::endl; 21 } 22};
Factory.hpp
file to create an abstract factory and concrete factories for different operating systems and their UI components:
C++1// Abstract Factory class interface for creating buttons and checkboxes 2class GUIFactory { 3public: 4 virtual Button* createButton() = 0; 5 virtual Checkbox* createCheckbox() = 0; 6 virtual ~GUIFactory() = default; 7}; 8 9// Concrete Factory WinFactory that creates Windows style buttons and checkboxes by implementing GUIFactory 10class WinFactory : public GUIFactory { 11public: 12 Button* createButton() override { 13 return new WinButton(); 14 } 15 16 Checkbox* createCheckbox() override { 17 return new WinCheckbox(); 18 } 19}; 20 21// Concrete Factory MacFactory that creates Mac style buttons and checkboxes by implementing GUIFactory 22class MacFactory : public GUIFactory { 23public: 24 Button* createButton() override { 25 return new MacButton(); 26 } 27 28 Checkbox* createCheckbox() override { 29 return new MacCheckbox(); 30 } 31};
Application.hpp
file to create an application class that interacts with the abstract factory:
C++1// Client code that interacts with the abstract factory to create related objects 2class Application { 3private: 4 GUIFactory* factory; 5 Button* button; 6 Checkbox* checkbox; 7 8public: 9 Application(GUIFactory* f) : factory(f) { 10 button = factory->createButton(); 11 checkbox = factory->createCheckbox(); 12 } 13 14 void paint() { 15 button->paint(); 16 checkbox->paint(); 17 } 18 19 ~Application() { 20 delete button; 21 delete checkbox; 22 } 23};
main.cpp
file to test the code:
C++1int main() { 2 GUIFactory* factory = nullptr; 3 std::string osType = "Windows"; 4 5 // Create a factory based on the OS type 6 if (osType == "Windows") { 7 factory = new WinFactory(); 8 } else if (osType == "Mac") { 9 factory = new MacFactory(); 10 } 11 12 if (factory) { 13 // Create an application using the factory and paint the UI components 14 Application* app = new Application(factory); 15 app->paint(); 16 17 delete app; 18 delete factory; 19 } else { 20 std::cout << "Unknown OS type." << std::endl; 21 } 22 23 return 0; 24}
This code snippet gives an insight into how our abstract factory can create related objects, such as buttons and checkboxes for different operating systems.
In the example above, we have two concrete factories, WinFactory
and MacFactory
, that create Windows and Mac style buttons and checkboxes. The Application
class interacts with the abstract factory to create the required objects without knowing the concrete classes. This decouples the client code from the object creation process, making it easier to switch between different object families.
In short for the Abstract Factory Pattern, we need to define abstract product classes and their concrete implementations (e.g., Button
, Checkbox
, WinButton
, MacButton
, WinCheckbox
, MacCheckbox
). Then, we create an abstract factory class and concrete factories for different object families (e.g., GUIFactory
, WinFactory
, MacFactory
). Finally, the client code interacts with the abstract factory to create related objects without knowing their concrete classes.
The Abstract Factory Pattern is useful when you need to create families of related objects without specifying their concrete classes. This pattern is beneficial in the following scenarios:
Let's also discuss the pros and cons of using the Abstract Factory Pattern:
The Abstract Factory Pattern and the Factory Method Pattern are both creational design patterns that deal with object creation. However, they serve different purposes and are used in distinct scenarios:
Mastering the Abstract Factory Pattern is crucial because it allows your code to switch factory classes easily. This leads to better separation of concerns and makes your applications more modular and easier to maintain. By encapsulating object creation, you gain the ability to manage complexity in large systems, where creating families of related objects is necessary. Whether you are developing cross-platform applications or scalable systems, this pattern provides a robust solution for consistent and reliable object creation.
Exciting, right? Let's move on to the practice section and begin implementing the Abstract Factory Pattern together.