Tuesday, January 06, 2026

Abstract Factory Design Pattern (C++

Abstract Factory Design Pattern (C++)

The Abstract Factory Design Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. Instead of instantiating objects directly, the creation logic is delegated to factory objects.

These factory objects are responsible for creating objects that belong to a common theme or family, ensuring that related objects are created together and remain compatible.

Why Study the Abstract Factory Pattern?

Studying the Abstract Factory design pattern can be highly beneficial for a C++ developer for several reasons:

  • Code Maintenance: Simplifies system maintenance by isolating concrete classes and reducing dependencies.
  • System Scalability: Allows new product families to be added without changing existing client code.
  • Interchangeability: Makes it easy to swap entire product families at runtime.
  • Consistency: Ensures related objects are created together and work correctly as a group.
  • Product Variations: Supports multiple implementations without complicating client logic.
  • Integration Ease: New product types can be integrated smoothly.
  • C++ Efficiency: Centralizes object creation, encouraging better resource management.

By studying the Abstract Factory pattern in C++, developers learn how to design systems that handle growth and change gracefully, resulting in more robust and adaptable software.


Example: Domestic and Wild Animals

In this example, we use the Abstract Factory pattern to create families of animals. There are two families:

  • Domestic animals (e.g., Poodle, Domestic Cat)
  • Wild animals (e.g., Hyena, Lion)

The client code does not know which concrete classes are being instantiated. It interacts only with abstract interfaces.


Animal.h


#ifndef ANIMAL_H
#define ANIMAL_H

#include <string>

class Animal {
public:
    virtual ~Animal() {}
    virtual std::string makeSound() const = 0;
    virtual std::string getName() const = 0;
};

#endif

Dog.h


#ifndef DOG_H
#define DOG_H

#include "Animal.h"

class Dog : public Animal {};

#endif

Cat.h


#ifndef CAT_H
#define CAT_H

#include "Animal.h"

class Cat : public Animal {};

#endif

Poodle.h


#ifndef POODLE_H
#define POODLE_H

#include "Dog.h"

class Poodle : public Dog {
public:
    std::string makeSound() const override {
        return "Woof! I'm a Poodle!";
    }
    std::string getName() const override {
        return "Poodle";
    }
};

#endif

Hyena.h


#ifndef HYENA_H
#define HYENA_H

#include "Dog.h"

class Hyena : public Dog {
public:
    std::string makeSound() const override {
        return "Laugh! I'm a Hyena!";
    }
    std::string getName() const override {
        return "Hyena";
    }
};

#endif

DomesticCat.h


#ifndef DOMESTICCAT_H
#define DOMESTICCAT_H

#include "Cat.h"

class DomesticCat : public Cat {
public:
    std::string makeSound() const override {
        return "Meow! I'm a Domestic Cat!";
    }
    std::string getName() const override {
        return "Domestic Cat";
    }
};

#endif

Lion.h


#ifndef LION_H
#define LION_H

#include "Cat.h"

class Lion : public Cat {
public:
    std::string makeSound() const override {
        return "Roar! I'm a Lion!";
    }
    std::string getName() const override {
        return "Lion";
    }
};

#endif

AnimalFactory.h


#ifndef ANIMALFACTORY_H
#define ANIMALFACTORY_H

#include "Dog.h"
#include "Cat.h"

class AnimalFactory {
public:
    virtual Dog* createDog() const = 0;
    virtual Cat* createCat() const = 0;
    virtual ~AnimalFactory() {}
};

#endif

DomesticAnimalFactory.h


#ifndef DOMESTICANIMALFACTORY_H
#define DOMESTICANIMALFACTORY_H

#include "AnimalFactory.h"
#include "Poodle.h"
#include "DomesticCat.h"

class DomesticAnimalFactory : public AnimalFactory {
public:
    Dog* createDog() const override {
        return new Poodle();
    }
    Cat* createCat() const override {
        return new DomesticCat();
    }
};

#endif

WildAnimalFactory.h


#ifndef WILDANIMALFACTORY_H
#define WILDANIMALFACTORY_H

#include "AnimalFactory.h"
#include "Hyena.h"
#include "Lion.h"

class WildAnimalFactory : public AnimalFactory {
public:
    Dog* createDog() const override {
        return new Hyena();
    }
    Cat* createCat() const override {
        return new Lion();
    }
};

#endif

main.cpp


#include <iostream>
#include <memory>
#include "DomesticAnimalFactory.h"
#include "WildAnimalFactory.h"

int main() {
    auto domesticFactory = std::make_unique<DomesticAnimalFactory>();
    auto domesticDog = std::unique_ptr<Dog>(domesticFactory->createDog());
    auto domesticCat = std::unique_ptr<Cat>(domesticFactory->createCat());

    std::cout << domesticDog->makeSound() << " I am a " << domesticDog->getName() << std::endl;
    std::cout << domesticCat->makeSound() << " I am a " << domesticCat->getName() << std::endl;

    auto wildFactory = std::make_unique<WildAnimalFactory>();
    auto wildDog = std::unique_ptr<Dog>(wildFactory->createDog());
    auto wildCat = std::unique_ptr<Cat>(wildFactory->createCat());

    std::cout << wildDog->makeSound() << " I am a " << wildDog->getName() << std::endl;
    std::cout << wildCat->makeSound() << " I am a " << wildCat->getName() << std::endl;

    return 0;
}

S.W.O.T. Analysis

Strengths

  • Decouples client code from concrete implementations
  • Ensures consistency across product families
  • Improves scalability and extensibility

Weaknesses

  • Introduces additional classes and interfaces
  • Can increase overall system complexity

Opportunities

  • Leverages modern C++ features like smart pointers
  • Combines well with other design patterns

Threats

  • Risk of overengineering for small systems
  • Potential performance overhead due to abstraction

No comments:

Abstract Factory Design Pattern (C++

Abstract Factory Design Pattern (C++) The Abstract Factory Design Pattern is a creational design pattern that provides an interface for...