Menu
Coddy logo textTech

Factory y Abstract Factory

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy. Lección 92 de 104.

El patrón Factory delega la creación de objetos a un método o una clase independientes, lo que permite crear objetos sin especificar su clase exacta. Esto resulta útil cuando la lógica de creación es compleja o cuando quieres desacoplar el código del cliente de las implementaciones concretas.

Una fábrica simple utiliza un método que devuelve diferentes tipos derivados según la entrada:

#include <iostream>
#include <memory>

class Button {
public:
    virtual void render() = 0;
    virtual ~Button() = default;
};

class WindowsButton : public Button {
public:
    void render() override { std::cout << "Windows button\n"; }
};

class MacButton : public Button {
public:
    void render() override { std::cout << "Mac button\n"; }
};

// Función de fábrica
std::unique_ptr<Button> createButton(const std::string& os) {
    if (os == "windows") return std::make_unique<WindowsButton>();
    if (os == "mac") return std::make_unique<MacButton>();
    return nullptr;
}

La fábrica abstracta lleva esto más lejos al crear familias de objetos relacionados. En lugar de un único método de fábrica, tienes una interfaz de fábrica con múltiples métodos de creación:

class Checkbox {
public:
    virtual void check() = 0;
    virtual ~Checkbox() = default;
};

class WindowsCheckbox : public Checkbox {
public:
    void check() override { std::cout << "Windows checkbox\n"; }
};

class MacCheckbox : public Checkbox {
public:
    void check() override { std::cout << "Mac checkbox\n"; }
};

// Fábrica Abstracta
class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
    virtual std::unique_ptr<Checkbox> createCheckbox() = 0;
    virtual ~GUIFactory() = default;
};

class WindowsFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WindowsButton>();
    }
    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<WindowsCheckbox>();
    }
};

Usa Factory cuando necesites una creación flexible de objetos y Abstract Factory cuando necesites garantizar que los objetos relacionados funcionen juntos de manera coherente.

challenge icon

Desafío

Fácil

Construyamos un sistema de Generación de documentos utilizando los patrones Factory y Abstract Factory. Crearás un sistema capaz de generar distintos tipos de documentos (informes y facturas) para diferentes formatos de salida (PDF y HTML), demostrando cómo las fábricas desacoplan la creación de objetos del código cliente.

Organizarás tu código en cuatro archivos:

  • Document.h: Define la jerarquía de productos de documentos.

    Crea una clase base abstracta Document con un método virtual puro generate() que devuelva una cadena que describa el documento generado, y un destructor virtual.

    Después crea cuatro clases de documentos concretas:

    • PDFReport: generate() devuelve "Generating PDF Report"
    • HTMLReport: generate() devuelve "Generating HTML Report"
    • PDFInvoice: generate() devuelve "Generating PDF Invoice"
    • HTMLInvoice: generate() devuelve "Generating HTML Invoice"
  • DocumentFactory.h: Implementa tanto una función de fábrica simple como una fábrica abstracta.

    Primero, crea una función de fábrica simple llamada createDocument que reciba dos cadenas: un tipo de documento ("report" o "invoice") y un formato ("pdf" o "html"). Debe devolver un std::unique_ptr<Document> que apunte al documento concreto correspondiente. Devuelve nullptr para combinaciones no válidas.

    Después crea una clase de fábrica abstracta llamada DocumentFactory con dos métodos virtuales puros:

    • createReport(): devuelve un std::unique_ptr<Document>
    • createInvoice(): devuelve un std::unique_ptr<Document>

    Implementa dos fábricas concretas:

    • PDFFactory: crea PDFReport y PDFInvoice
    • HTMLFactory: crea HTMLReport y HTMLInvoice
  • DocumentService.h: Crea un servicio que utilice la fábrica abstracta.

    Define una clase DocumentService que reciba un std::unique_ptr<DocumentFactory> en su constructor. Debe tener un método llamado generateAllDocuments() que utilice la fábrica para crear tanto un informe como una factura y, después, imprima el resultado de llamar a generate() en cada uno, uno por línea.

  • main.cpp: Demuestra ambos enfoques de fábrica.

    Lee dos entradas:

    1. Un tipo de documento (report o invoice)
    2. Un formato (pdf o html)

    Primero, utiliza la función de fábrica simple para crear un documento según las entradas. Imprime el resultado de llamar a generate() en él.

    Después imprime una línea en blanco.

    A continuación, crea un DocumentService con la fábrica adecuada según la entrada de formato (usa PDFFactory para pdf y HTMLFactory para html). Llama a generateAllDocuments() para mostrar cómo la fábrica abstracta crea una familia de documentos relacionados.

Por ejemplo, con las entradas report y pdf:

Generating PDF Report

Generating PDF Report
Generating PDF Invoice

Con las entradas invoice y html:

Generating HTML Invoice

Generating HTML Report
Generating HTML Invoice

Observa cómo la fábrica simple crea un único documento basándose en ambos parámetros, mientras que la fábrica abstracta garantiza que todos los documentos creados por un servicio compartan el mismo formato. Este es el principal beneficio de Abstract Factory cuando necesitas familias de objetos relacionados que funcionen juntas de manera coherente.

Pruébalo tú mismo

#include <iostream>
#include <string>
#include <memory>
#include "Document.h"
#include "DocumentFactory.h"
#include "DocumentService.h"

using namespace std;

int main() {
    // Leer entradas
    string documentType;
    string format;
    cin >> documentType;
    cin >> format;
    
    // TODO: Usa la función de fábrica simple para crear un documento
    // basado en las entradas documentType y format
    // Imprime el resultado de llamar a generate() en él
    
    // Imprime una línea en blanco
    cout << endl;
    
    // TODO: Crea un DocumentService con la fábrica apropiada
    // basado en la entrada format (PDFFactory para "pdf", HTMLFactory para "html")
    // Llama a generateAllDocuments() para demostrar la fábrica abstracta
    
    return 0;
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos

Practica por tu cuenta: Compilador de C++ online