Menu
Coddy logo textTech

Padrão de Método Template

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 94 de 107.

O padrão Template Method define o esqueleto de um algoritmo em um tipo base, permitindo que os subtipos substituam etapas específicas sem alterar a estrutura geral. Enquanto o Decorator adiciona comportamento envolvendo objetos, o Template Method controla o fluxo do algoritmo e permite a personalização de etapas individuais.

Em Go, como não há herança, implementamos esse padrão usando incorporação de structs combinada com interfaces. A struct "template" define a estrutura do algoritmo e chama métodos que podem 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)
}

As implementações concretas fornecem suas próprias versões de cada etapa, enquanto o fluxo do algoritmo permanece inalterado:

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 }

O método template Execute orquestra as etapas em uma ordem fixa:

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

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

O Template Method é ideal quando você tem algoritmos que compartilham a mesma estrutura, mas diferem em etapas específicas, como pipelines de importação/exportação de dados, geradores de relatórios ou frameworks de teste.

challenge icon

Desafio

Fácil

Vamos criar um sistema de geração de relatórios usando o padrão Template Method! Você criará uma estrutura na qual diferentes tipos de relatório seguem o mesmo processo de geração, coletando dados, formatando-os e produzindo o resultado, mas cada tipo de relatório personaliza essas etapas de maneira diferente.

Você organizará seu código em três arquivos:

  • report.go: Defina sua interface e o processador base que coordena o algoritmo de geração do relatório.

    Crie uma interface ReportGenerator com três métodos que representam as etapas da geração do relatório:

    • GatherData() string: recupera os dados brutos do relatório
    • FormatData(data string) string: transforma os dados no formato do relatório
    • OutputReport(formatted string) string: produz a mensagem de saída final

    Crie uma struct ReportProcessor que contenha uma implementação de ReportGenerator. Adicione um método Generate() string que execute as três etapas na ordem: coletar, formatar e, em seguida, produzir a saída, retornando o resultado final.

  • generators.go: Implemente geradores de relatórios concretos que personalizem cada etapa.

    Crie dois tipos de relatório:

    • SalesReport com um campo Region (string)
      • GatherData() retorna sales-data-[region]
      • FormatData(data) retorna SALES REPORT: [data]
      • OutputReport(formatted) retorna Printed: [formatted]
    • InventoryReport com um campo Warehouse (string)
      • GatherData() retorna inventory-[warehouse]
      • FormatData(data) retorna *** [data] ***
      • OutputReport(formatted) retorna Exported: [formatted]
  • main.go: Demonstre como a mesma estrutura de algoritmo produz resultados diferentes com base na implementação.

    Leia o tipo de relatório (sales ou inventory) e o valor de configuração (região para vendas, armazém para inventário). Crie o gerador apropriado, envolva-o em um ReportProcessor, chame Generate() e imprima o resultado.

As seguintes entradas serão fornecidas:

  • Linha 1: Tipo de relatório (sales ou inventory)
  • Linha 2: Valor de configuração (nome da região ou nome do armazém)

Por exemplo, dado:

sales
North

Sua saída deve ser:

Printed: SALES REPORT: sales-data-North

E, dado:

inventory
MainHub

Sua saída deve ser:

Exported: *** inventory-MainHub ***

E, dado:

sales
West

Sua saída deve ser:

Printed: SALES REPORT: sales-data-West

Observe como o ReportProcessor sempre chama as mesmas três etapas na mesma ordem, mas cada tipo de relatório fornece sua própria implementação dessas etapas. O esqueleto do algoritmo permanece fixo, enquanto os detalhes variam: esse é o padrão Template Method em ação!

Experimente você mesmo

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Ler o tipo de relatório
	scanner.Scan()
	reportType := scanner.Text()
	
	// Ler o valor de configuração (região ou armazém)
	scanner.Scan()
	configValue := scanner.Text()

	// TODO: Crie o gerador apropriado com base em reportType
	// - Se reportType for "sales", crie um SalesReport com Region definido como configValue
	// - Se reportType for "inventory", crie um InventoryReport com Warehouse definido como configValue
	
	// TODO: Crie um ReportProcessor com o gerador
	
	// TODO: Chame Generate() e imprima o resultado
	_ = reportType
	_ = configValue
	fmt.Println("TODO: Generate and print the report")
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Go online