Menu
Coddy logo textTech

Patrón Template Method

Parte de la sección Programación Orientada a Objetos del Journey de GO de Coddy — lección 94 de 107.

El patrón Template Method define el esqueleto de un algoritmo en un tipo base, permitiendo que los subtipos sobrescriban pasos específicos sin cambiar la estructura general. Mientras que Decorator añade comportamiento envolviendo objetos, Template Method controla el flujo del algoritmo y permite la personalización de pasos individuales.

En Go, dado que no existe la herencia, implementamos este patrón utilizando la incrustación de estructuras (struct embedding) combinada con interfaces. La estructura "plantilla" define la estructura del algoritmo y llama a métodos que pueden ser personalizados:

type DataProcessor interface {
    ReadData() string
    ProcessData(data string) string
    SaveData(result string) string
}

type BaseProcessor struct {
    Impl DataProcessor
}

func (b *BaseProcessor) Execute() string {
    data := b.Impl.ReadData()
    result := b.Impl.ProcessData(data)
    return b.Impl.SaveData(result)
}

Las implementaciones concretas proporcionan sus propias versiones de cada paso mientras que el flujo del algoritmo permanece sin cambios:

type CSVProcessor struct{}

func (c CSVProcessor) ReadData() string       { return "csv-data" }
func (c CSVProcessor) ProcessData(d string) string { return "processed-" + d }
func (c CSVProcessor) SaveData(r string) string    { return "Saved: " + r }

type JSONProcessor struct{}

func (j JSONProcessor) ReadData() string       { return "json-data" }
func (j JSONProcessor) ProcessData(d string) string { return "parsed-" + d }
func (j JSONProcessor) SaveData(r string) string    { return "Stored: " + r }

El método de plantilla Execute orquesta los pasos en un orden fijo:

csvProc := &BaseProcessor{Impl: CSVProcessor{}}
fmt.Println(csvProc.Execute())  // Guardado: processed-csv-data

jsonProc := &BaseProcessor{Impl: JSONProcessor{}}
fmt.Println(jsonProc.Execute()) // Almacenado: parsed-json-data

Template Method es ideal cuando tienes algoritmos que comparten la misma estructura pero difieren en pasos específicos, como flujos de importación/exportación de datos, generadores de informes o frameworks de pruebas.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de generación de informes utilizando el patrón Template Method! Crearás un marco de trabajo donde diferentes tipos de informes siguen el mismo proceso de generación (recopilación de datos, formateo y salida del resultado), pero cada tipo de informe personaliza estos pasos de manera diferente.

Organizarás tu código en tres archivos:

  • report.go: Define tu interfaz y el procesador base que orquesta el algoritmo de generación de informes.

    Crea una interfaz ReportGenerator con tres métodos que representen los pasos de la generación de informes:

    • GatherData() string — recupera los datos brutos para el informe
    • FormatData(data string) string — transforma los datos al formato del informe
    • OutputReport(formatted string) string — produce el mensaje de salida final

    Construye una estructura ReportProcessor que contenga una implementación de ReportGenerator. Añade un método Generate() string que ejecute los tres pasos en orden: recopilar, formatear y luego dar salida, devolviendo el resultado final.

  • generators.go: Implementa generadores de informes concretos que personalicen cada paso.

    Crea dos tipos de informes:

    • SalesReport con un campo Region (string)
      • GatherData() devuelve "sales-data-" + el valor de la región
      • FormatData(data) devuelve "SALES REPORT: " + el valor de data
      • OutputReport(formatted) devuelve "Printed: " + el valor de formatted
    • InventoryReport con un campo Warehouse (string)
      • GatherData() devuelve "inventory-" + el valor del almacén
      • FormatData(data) devuelve "*** " + el valor de data + " ***"
      • OutputReport(formatted) devuelve "Exported: " + el valor de formatted
  • main.go: Demuestra cómo la misma estructura de algoritmo produce diferentes resultados según la implementación.

    Lee el tipo de informe ("sales" o "inventory") y el valor de configuración (región para ventas, almacén para inventario). Crea el generador apropiado, envuélvelo en un ReportProcessor, llama a Generate() e imprime el resultado.

Se proporcionarán las siguientes entradas:

  • Línea 1: Tipo de informe ("sales" o "inventory")
  • Línea 2: Valor de configuración (nombre de la región o nombre del almacén)

Por ejemplo, dado:

sales
North

Tu salida debería ser:

Printed: SALES REPORT: sales-data-North

Y dado:

inventory
MainHub

Tu salida debería ser:

Exported: *** inventory-MainHub ***

Y dado:

sales
West

Tu salida debería ser:

Printed: SALES REPORT: sales-data-West

Observa cómo el ReportProcessor siempre llama a los mismos tres pasos en el mismo orden, pero cada tipo de informe proporciona su propia implementación de esos pasos. El esqueleto del algoritmo permanece fijo mientras los detalles varían: ¡ese es el patrón Template Method en acción!

Hoja de referencia

El patrón Template Method define el esqueleto de un algoritmo en un tipo base, permitiendo que los subtipos sobrescriban pasos específicos sin cambiar la estructura general.

En Go, implemente este patrón utilizando la incrustación de estructuras (struct embedding) combinada con interfaces. La estructura "template" define la estructura del algoritmo y llama a métodos que pueden ser personalizados:

type DataProcessor interface {
    ReadData() string
    ProcessData(data string) string
    SaveData(result string) string
}

type BaseProcessor struct {
    Impl DataProcessor
}

func (b *BaseProcessor) Execute() string {
    data := b.Impl.ReadData()
    result := b.Impl.ProcessData(data)
    return b.Impl.SaveData(result)
}

Las implementaciones concretas proporcionan sus propias versiones de cada paso mientras que el flujo del algoritmo permanece sin cambios:

type CSVProcessor struct{}

func (c CSVProcessor) ReadData() string       { return "csv-data" }
func (c CSVProcessor) ProcessData(d string) string { return "processed-" + d }
func (c CSVProcessor) SaveData(r string) string    { return "Saved: " + r }

type JSONProcessor struct{}

func (j JSONProcessor) ReadData() string       { return "json-data" }
func (j JSONProcessor) ProcessData(d string) string { return "parsed-" + d }
func (j JSONProcessor) SaveData(r string) string    { return "Stored: " + r }

El método de plantilla orquesta los pasos en un orden fijo:

csvProc := &BaseProcessor{Impl: CSVProcessor{}}
fmt.Println(csvProc.Execute())  // Saved: processed-csv-data

jsonProc := &BaseProcessor{Impl: JSONProcessor{}}
fmt.Println(jsonProc.Execute()) // Stored: parsed-json-data

Template Method es ideal cuando los algoritmos comparten la misma estructura pero difieren en pasos específicos, como los flujos de importación/exportación de datos, generadores de informes o marcos de pruebas.

Pruébalo tú mismo

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Leer el tipo de informe
	scanner.Scan()
	reportType := scanner.Text()
	
	// Leer el valor de configuración (región o almacén)
	scanner.Scan()
	configValue := scanner.Text()

	// TODO: Crear el generador apropiado basado en reportType
	// - Si reportType es "sales", crear un SalesReport con Region establecido en configValue
	// - Si reportType es "inventory", crear un InventoryReport con Warehouse establecido en configValue
	
	// TODO: Crear un ReportProcessor con el generador
	
	// TODO: Llamar a Generate() e imprimir el resultado
	_ = reportType
	_ = configValue
	fmt.Println("TODO: Generate and print the report")
}
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