Saltar al contenido

Template Method

Un patrón de comportamiento: la clase base fija la secuencia del algoritmo, y las subclases completan los pasos que varían.

7 min. de lectura

Template Method es un patrón de comportamiento que define el esqueleto de un algoritmo en una clase base, delegando en las subclases la implementación de algunos de sus pasos.

El problema

AndesShop genera distintos tipos de reportes internos: un reporte diario de ventas, un reporte de inventario, un reporte de devoluciones. Los tres siguen la misma secuencia general — obtener los datos, armar un encabezado, formatear el cuerpo, agregar un pie con totales, y exportarlo — pero cada uno obtiene y formatea datos distintos. Si cada tipo de reporte implementa esa secuencia completa por su cuenta, los pasos comunes (encabezado, exportación, estructura general) terminan duplicados en cada clase de reporte, y un cambio en esa estructura común hay que replicarlo en todas.

La solución

Template Method define el algoritmo completo una sola vez, en una clase base, como una secuencia fija de llamadas a métodos — algunos ya implementados (los pasos comunes), otros abstractos (los pasos que varían). Cada subclase concreta solo implementa los pasos que le son propios; el orden y la estructura general quedan fijos en la clase base y no se pueden alterar por accidente.

Estructura de Template Method: la clase base fija el esqueleto en un método final y delega solo los pasos variables.

Ejemplo en Java

abstract class ReportGenerator {
    // El Template Method: fija la secuencia, no se puede reordenar desde las subclases
    public final String generate() {
        StringBuilder report = new StringBuilder();
        report.append(buildHeader());
        report.append(formatBody(fetchData()));
        report.append(buildFooter());
        return report.toString();
    }

    protected abstract List<?> fetchData();
    protected abstract String formatBody(List<?> data);

    // Pasos comunes, ya resueltos en la clase base
    protected String buildHeader() { return "=== AndesShop Report ===\n"; }
    protected String buildFooter() { return "=== End of report ===\n"; }
}

class DailySalesReport extends ReportGenerator {
    private final SalesRepository salesRepository;

    public DailySalesReport(SalesRepository salesRepository) {
        this.salesRepository = salesRepository;
    }

    protected List<?> fetchData() {
        return salesRepository.findForToday();
    }
    protected String formatBody(List<?> data) {
        return "Sales today: " + data.size() + " orders\n";
    }
}

class InventoryReport extends ReportGenerator {
    private final InventoryRepository inventoryRepository;

    public InventoryReport(InventoryRepository inventoryRepository) {
        this.inventoryRepository = inventoryRepository;
    }

    protected List<?> fetchData() {
        return inventoryRepository.findLowStock();
    }
    protected String formatBody(List<?> data) {
        return "Low stock items: " + data.size() + "\n";
    }
}
ReportGenerator report = new DailySalesReport(salesRepository);
System.out.println(report.generate()); // encabezado + cuerpo propio + pie, siempre en ese orden

Cuándo usarlo

  • Cuando varias clases implementan un algoritmo con la misma estructura general, pero difieren en pasos puntuales.
  • Cuando querés controlar en qué puntos exactos del algoritmo las subclases pueden introducir variaciones, sin darles control sobre la secuencia completa.

Cuándo evitarlo

Variantes de algoritmo que difieren demasiado entre sí —sin una secuencia común real— no encajan bien si se las fuerza dentro del mismo esqueleto: terminan generando métodos abstractos vacíos o irrelevantes en algunas subclases.

Ventajas y desventajas

VentajasDesventajas
Elimina la duplicación de los pasos comunes entre variantes de un mismo algoritmoLas subclases quedan atadas a la estructura fija que define la clase base
Centraliza el control del flujo general en un solo lugarPuede volverse difícil de seguir si la jerarquía de subclases crece demasiado
Facilita agregar variantes nuevas: solo hay que implementar los pasos abstractos

Relación con otros patrones

  • Se apoya frecuentemente en Factory Method como uno de sus pasos abstractos.
  • Comparte con Strategy el objetivo de variar parte de un comportamiento, pero lo hace con herencia en vez de composición — Strategy suele preferirse cuando se necesita cambiar el algoritmo en tiempo de ejecución.

Te sirvió, compartilo

// ¿te sirvió?
// compartilo