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, lo que permite que los subtipos redefinan 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 personalizar pasos individuales.

En Go, como no existe la herencia, implementamos este patrón usando la inclusión de estructuras combinada con interfaces. La estructura de «plantilla» define la estructura del algoritmo y llama a métodos que se pueden personalizar:

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 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 canalizaciones de importación/exportación de datos, generadores de informes o marcos de pruebas.

challenge icon

Desafío

Fácil

¡Construyamos un sistema de generación de informes usando el patrón Template Method! Crearás un marco en el que los distintos tipos de informes siguen el mismo proceso de generación, recopilando datos, dándoles formato y generando el 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 coordina el algoritmo de generación del informe.

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

    • GatherData() string: recupera los datos sin procesar del 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. Agrega un método Generate() string que ejecute los tres pasos en orden: recopilar, dar formato y después generar la salida; este método debe devolver 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-[region]
      • FormatData(data) devuelve SALES REPORT: [data]
      • OutputReport(formatted) devuelve Printed: [formatted]
    • InventoryReport con un campo Warehouse (string)
      • GatherData() devuelve inventory-[warehouse]
      • FormatData(data) devuelve *** [data] ***
      • OutputReport(formatted) devuelve Exported: [formatted]
  • main.go: Demuestra cómo la misma estructura algorítmica produce resultados diferentes según la implementación.

    Lee el tipo de informe (sales o inventory) y el valor de configuración (la región para sales o el almacén para inventory). Crea el generador correspondiente, 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, dada la siguiente entrada:

sales
North

Tu salida debería ser:

Printed: SALES REPORT: sales-data-North

Y dada la siguiente entrada:

inventory
MainHub

Tu salida debería ser:

Exported: *** inventory-MainHub ***

Y dada la siguiente entrada:

sales
West

Tu salida debería ser:

Printed: SALES REPORT: sales-data-West

Observa cómo 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!

Pruébalo tú mismo

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Leer el tipo de reporte
	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 según reportType
	// - Si reportType es "sales", crear un SalesReport con Region establecido a configValue
	// - Si reportType es "inventory", crear un InventoryReport con Warehouse establecido a 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

Practica por tu cuenta: Compilador de Go online