Menu
Coddy logo textTech

Patrón Template Method

Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 99 de 104.

El patrón Template Method define el esqueleto de un algoritmo en una clase base, permitiendo que las subclases sobrescriban pasos específicos sin cambiar la estructura general del algoritmo. A diferencia de Strategy, que intercambia algoritmos completos, Template Method mantiene el algoritmo fijo mientras permite la personalización de pasos individuales.

La clase base implementa el método de plantilla (el algoritmo) y llama a métodos abstractos o virtuales que las subclases deben proporcionar:

#include <iostream>

class DataProcessor {
public:
    // Método de plantilla - define el esqueleto del algoritmo
    void process() {
        loadData();
        processData();
        saveResults();
    }
    
    virtual ~DataProcessor() = default;
    
protected:
    virtual void loadData() = 0;      // Debe ser implementado
    virtual void processData() = 0;   // Debe ser implementado
    
    // Hook - anulación opcional con comportamiento por defecto
    virtual void saveResults() {
        std::cout << "Saving to default location\n";
    }
};

class CSVProcessor : public DataProcessor {
protected:
    void loadData() override {
        std::cout << "Loading CSV file\n";
    }
    void processData() override {
        std::cout << "Parsing CSV data\n";
    }
};

class JSONProcessor : public DataProcessor {
protected:
    void loadData() override {
        std::cout << "Loading JSON file\n";
    }
    void processData() override {
        std::cout << "Parsing JSON data\n";
    }
    void saveResults() override {
        std::cout << "Saving to cloud storage\n";
    }
};

int main() {
    CSVProcessor csv;
    csv.process();  // Usa saveResults por defecto
    
    JSONProcessor json;
    json.process(); // Usa saveResults personalizado
}

El método process() es el método de plantilla: define la secuencia fija de pasos. Las subclases implementan loadData() y processData() de manera diferente, pero el orden nunca cambia. El método saveResults() es un "hook" (gancho): tiene una implementación predeterminada que las subclases pueden sobrescribir opcionalmente.

Utiliza Template Method cuando tengas un algoritmo con pasos invariantes pero necesites flexibilidad en operaciones específicas, o cuando quieras evitar la duplicación de código en clases similares.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de Generador de Informes utilizando el patrón Template Method. Crearás un marco de trabajo donde diferentes tipos de informes (como informes de ventas e informes de inventario) siguen el mismo proceso de generación, pero cada tipo de informe personaliza pasos específicos. Este es un escenario perfecto para el Template Method: el flujo de trabajo general permanece fijo mientras que los pasos individuales varían.

Organizarás tu código en tres archivos:

  • ReportGenerator.h: Define la clase base abstracta con el método de plantilla.

    Crea una clase ReportGenerator que defina el esqueleto del algoritmo de generación de informes. Tu método de plantilla generateReport() debe ejecutar estos pasos en orden:

    1. gatherData() — virtual puro, debe ser implementado por las subclases
    2. formatReport() — virtual puro, debe ser implementado por las subclases
    3. addHeader() — un "hook" con comportamiento por defecto que imprime --- Report ---
    4. printReport() — virtual puro, debe ser implementado por las subclases

    El método addHeader() sirve como un "hook" que las subclases pueden opcionalmente sobrescribir para personalizar el encabezado.

  • Reports.h: Implementa dos generadores de informes concretos.

    Crea una clase SalesReport que:

    • gatherData() imprima Gathering sales data from database
    • formatReport() imprima Formatting sales figures
    • printReport() imprima Sales Total: $[amount] donde amount se pasa al constructor

    Crea una clase InventoryReport que:

    • gatherData() imprima Scanning inventory records
    • formatReport() imprima Organizing inventory by category
    • addHeader() sobrescriba el "hook" para imprimir === Inventory Report ===
    • printReport() imprima Items in stock: [count] donde count se pasa al constructor

    Ambas clases deben aceptar sus respectivos valores (amount o count) a través de sus constructores.

  • main.cpp: Demuestra el patrón Template Method.

    Lee dos entradas:

    1. Monto de ventas (entero)
    2. Cantidad de inventario (entero)

    Crea un SalesReport con el monto de ventas y genéralo. Luego crea un InventoryReport con la cantidad de inventario y genéralo. Imprime una línea en blanco entre los dos informes para mayor legibilidad.

Por ejemplo, con las entradas 15000 y 250:

Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $15000

Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 250

Con las entradas 8500 y 120:

Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $8500

Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 120

Observa cómo ambos informes siguen exactamente la misma secuencia de pasos definida en generateReport(), pero cada uno implementa esos pasos de manera diferente. El InventoryReport también demuestra la sobrescritura del método "hook" para personalizar el encabezado, mientras que SalesReport utiliza el predeterminado. Este es el patrón Template Method en acción: la estructura del algoritmo está bloqueada en la clase base, pero los detalles son flexibles.

Hoja de referencia

El patrón Template Method define el esqueleto de un algoritmo en una clase base, permitiendo que las subclases sobrescriban pasos específicos sin cambiar la estructura general del algoritmo.

La clase base implementa el método de plantilla (el algoritmo) y llama a métodos abstractos o virtuales que las subclases deben proporcionar:

#include <iostream>

class DataProcessor {
public:
    // Método de plantilla - define el esqueleto del algoritmo
    void process() {
        loadData();
        processData();
        saveResults();
    }
    
    virtual ~DataProcessor() = default;
    
protected:
    virtual void loadData() = 0;      // Debe ser implementado
    virtual void processData() = 0;   // Debe ser implementado
    
    // Hook - sobrescritura opcional con comportamiento por defecto
    virtual void saveResults() {
        std::cout << "Saving to default location\n";
    }
};

class CSVProcessor : public DataProcessor {
protected:
    void loadData() override {
        std::cout << "Loading CSV file\n";
    }
    void processData() override {
        std::cout << "Parsing CSV data\n";
    }
};

class JSONProcessor : public DataProcessor {
protected:
    void loadData() override {
        std::cout << "Loading JSON file\n";
    }
    void processData() override {
        std::cout << "Parsing JSON data\n";
    }
    void saveResults() override {
        std::cout << "Saving to cloud storage\n";
    }
};

El método de plantilla define la secuencia fija de pasos. Las subclases implementan los métodos abstractos de manera diferente, pero el orden nunca cambia. Los métodos hook tienen implementaciones por defecto que las subclases pueden sobrescribir opcionalmente.

Utilice Template Method cuando tenga un algoritmo con pasos invariantes pero necesite flexibilidad en operaciones específicas, o cuando desee evitar la duplicación de código en clases similares.

Pruébalo tú mismo

#include <iostream>
#include "Reports.h"

using namespace std;

int main() {
    // Leer las entradas
    int salesAmount;
    int inventoryCount;
    cin >> salesAmount;
    cin >> inventoryCount;
    
    // TODO: Crear un SalesReport con salesAmount y generarlo
    
    // TODO: Imprimir una línea en blanco entre los informes
    
    // TODO: Crear un InventoryReport con inventoryCount y generarlo
    
    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