#include <iostream>
#include <memory>
#include <vector>

/**
 * Factory Method Pattern Example: Vehicle Factory
 *
 * - Product: Vehicle
 * - ConcreteProduct: Car, Bike
 * - Creator: VehicleFactory
 * - ConcreteCreator: CarFactory, BikeFactory
 *
 * The factory method pattern defers object creation to subclasses. Clients create products
 * through the factory base class interface without knowing the specific product type,
 * achieving decoupling between creation logic and usage.
 */

// Product base class: Vehicle
class Vehicle {
public:
    virtual ~Vehicle() = default;
    virtual void drive() const = 0;  // Product operation
};

// Concrete product: Car
class Car : public Vehicle {
public:
    void drive() const override {
        std::cout << "Driving a car 🚗" << std::endl;
    }
};

// Concrete product: Bike
class Bike : public Vehicle {
public:
    void drive() const override {
        std::cout << "Riding a bike 🚲" << std::endl;
    }
};

// Creator base class: declares the factory method
class VehicleFactory {
public:
    virtual ~VehicleFactory() = default;

    // Factory method: pure virtual, implemented by subclasses
    virtual std::unique_ptr<Vehicle> createVehicle() const = 0;

    // Method that uses the product (demonstrates factory method usage)
    // This method defines steps for operating the product, but which product is created is determined by subclass
    void useVehicle() const {
        auto vehicle = createVehicle();  // Call factory method
        vehicle->drive();                // Use product
    }
};

// Concrete creator: produces cars
class CarFactory : public VehicleFactory {
public:
    std::unique_ptr<Vehicle> createVehicle() const override {
        return std::make_unique<Car>();
    }
};

// Concrete creator: produces bikes
class BikeFactory : public VehicleFactory {
public:
    std::unique_ptr<Vehicle> createVehicle() const override {
        return std::make_unique<Bike>();
    }
};

int main() {
    std::cout << "=== Factory Method Pattern Demo ===" << std::endl;

    // Using polymorphism: operate different factories through base class pointers/references
    std::vector<std::unique_ptr<VehicleFactory>> factories;
    factories.push_back(std::make_unique<CarFactory>());
    factories.push_back(std::make_unique<BikeFactory>());

    // Call useVehicle() through factory base class interface, internally calls factory method to create and use product
    std::cout << "\nUsing products through factory base class interface:" << std::endl;
    for (const auto& factory : factories) {
        factory->useVehicle();
    }

    // Can also directly get product objects for more fine-grained operations
    std::cout << "\nDirectly obtaining product objects:" << std::endl;
    CarFactory carFactory;
    auto car = carFactory.createVehicle();  // Get product object
    car->drive();                           // Use product

    // Without smart pointers, traditional approach requires manual delete, but smart pointers are recommended
    // This demonstrates factory method flexibility: even through factory base class reference, correct product can be created
    std::cout << "\nCreating product through base class reference:" << std::endl;
    VehicleFactory& factoryRef = carFactory;
    auto anotherCar = factoryRef.createVehicle();
    anotherCar->drive();

    return 0;
}

results matching ""

    No results matching ""