---
title: "Template Method em Rust: Traits com Métodos Default como Templates"
url: "https://rustlang.com.br/padroes/template-method/"
markdown_url: "https://rustlang.com.br/padroes/template-method.MD"
description: "Implementação completa do padrão Template Method em Rust com traits, métodos default, pontos de customização e exemplo prático de processador de arquivos com parsing configurável."
date: "2026-02-27"
author: "Equipe Rust Brasil"
---

# Template Method em Rust: Traits com Métodos Default como Templates

Implementação completa do padrão Template Method em Rust com traits, métodos default, pontos de customização e exemplo prático de processador de arquivos com parsing configurável.


O **Template Method** (Método Template) é um padrão comportamental que define o esqueleto de um algoritmo em uma operação, delegando alguns passos para subclasses. Em Rust, este padrão se implementa de forma natural com **traits** que possuem **métodos default**: o método default define o algoritmo geral, e métodos sem implementação padrão servem como **pontos de customização** que cada tipo deve implementar.

A beleza desta abordagem em Rust é que o compilador garante que todos os pontos de customização sejam implementados, enquanto o algoritmo geral é herdado automaticamente. Diferente de herança em OOP (que cria acoplamento), traits em Rust oferecem composição limpa sem os problemas do "frágil base class".

## Problema

Imagine que você precisa processar diferentes tipos de arquivos (CSV, JSON, XML). O fluxo é sempre o mesmo: abrir o arquivo, ler o conteúdo, parsear os dados, validar, transformar e produzir resultado. Mas cada formato tem sua própria lógica de parsing e validação.

Sem o Template Method, cada processador repetiria toda a lógica do fluxo:

```rust
// ANTI-PADRÃO: código duplicado em cada processador
fn processar_csv(caminho: &str) -> Result<Vec<Registro>, Erro> {
    let conteudo = ler_arquivo(caminho)?;  // duplicado
    let dados = parsear_csv(&conteudo)?;   // específico
    validar_dados(&dados)?;                // duplicado
    let resultado = transformar(dados);     // duplicado
    Ok(resultado)
}

fn processar_json(caminho: &str) -> Result<Vec<Registro>, Erro> {
    let conteudo = ler_arquivo(caminho)?;  // duplicado
    let dados = parsear_json(&conteudo)?;  // específico
    validar_dados(&dados)?;                // duplicado
    let resultado = transformar(dados);     // duplicado
    Ok(resultado)
}
```

## Solução em Rust

### Template Method com Traits

```rust
use std::fmt;

/// Registro genérico — resultado do processamento
#[derive(Debug, Clone)]
struct Registro {
    campos: Vec<(String, String)>,
}

impl Registro {
    fn novo() -> Self {
        Registro { campos: Vec::new() }
    }

    fn adicionar(&mut self, chave: &str, valor: &str) {
        self.campos.push((chave.to_string(), valor.to_string()));
    }

    fn obter(&self, chave: &str) -> Option<&str> {
        self.campos.iter()
            .find(|(k, _)| k == chave)
            .map(|(_, v)| v.as_str())
    }
}

impl fmt::Display for Registro {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let campos: Vec<String> = self.campos.iter()
            .map(|(k, v)| format!("{}: {}", k, v))
            .collect();
        write!(f, "{{{}}}", campos.join(", "))
    }
}

/// Erros possíveis no processamento
#[derive(Debug)]
enum ErroProcessamento {
    Leitura(String),
    Parse(String),
    Validacao(String),
    Transformacao(String),
}

impl fmt::Display for ErroProcessamento {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ErroProcessamento::Leitura(m) => write!(f, "Erro de leitura: {}", m),
            ErroProcessamento::Parse(m) => write!(f, "Erro de parse: {}", m),
            ErroProcessamento::Validacao(m) => write!(f, "Erro de validação: {}", m),
            ErroProcessamento::Transformacao(m) => write!(f, "Erro de transformação: {}", m),
        }
    }
}

/// Trait com Template Method — define o algoritmo e os pontos de customização
trait ProcessadorArquivo {
    // ============================================================
    // TEMPLATE METHOD — define o fluxo completo (não deve ser sobrescrito)
    // ============================================================

    /// Processa um arquivo do início ao fim
    /// Este método default define o "template" — o esqueleto do algoritmo
    fn processar(&self, conteudo: &str) -> Result<Vec<Registro>, ErroProcessamento> {
        // Passo 1: Hooks de pré-processamento
        let conteudo_preparado = self.pre_processar(conteudo);

        // Passo 2: Parsing (OBRIGATÓRIO — cada formato implementa)
        println!("[{}] Parseando dados...", self.nome_formato());
        let registros = self.parsear(&conteudo_preparado)?;
        println!("[{}] {} registros parseados", self.nome_formato(), registros.len());

        // Passo 3: Validação (customizável, com default)
        println!("[{}] Validando registros...", self.nome_formato());
        let registros_validos = self.validar(registros)?;
        println!("[{}] {} registros válidos", self.nome_formato(), registros_validos.len());

        // Passo 4: Transformação (customizável, com default)
        println!("[{}] Transformando registros...", self.nome_formato());
        let resultado = self.transformar(registros_validos)?;

        // Passo 5: Hook pós-processamento
        self.pos_processar(&resultado);

        Ok(resultado)
    }

    // ============================================================
    // PONTOS DE CUSTOMIZAÇÃO — métodos abstratos (sem default)
    // ============================================================

    /// Nome do formato para logging
    fn nome_formato(&self) -> &str;

    /// Parse específico do formato — OBRIGATÓRIO
    fn parsear(&self, conteudo: &str) -> Result<Vec<Registro>, ErroProcessamento>;

    // ============================================================
    // HOOKS — métodos com implementação default (opcionais)
    // ============================================================

    /// Pré-processamento do conteúdo bruto
    /// Default: remove espaços em branco nas extremidades
    fn pre_processar(&self, conteudo: &str) -> String {
        conteudo.trim().to_string()
    }

    /// Validação dos registros parseados
    /// Default: aceita todos (sem validação)
    fn validar(&self, registros: Vec<Registro>) -> Result<Vec<Registro>, ErroProcessamento> {
        Ok(registros)
    }

    /// Transformação dos registros validados
    /// Default: retorna como está (sem transformação)
    fn transformar(&self, registros: Vec<Registro>) -> Result<Vec<Registro>, ErroProcessamento> {
        Ok(registros)
    }

    /// Hook pós-processamento
    /// Default: não faz nada
    fn pos_processar(&self, registros: &[Registro]) {
        let _ = registros; // Silencia warning de variável não usada
    }
}

// ============================================================
// Implementação: Processador CSV
// ============================================================

struct ProcessadorCsv {
    separador: char,
    tem_cabecalho: bool,
}

impl ProcessadorCsv {
    fn novo() -> Self {
        ProcessadorCsv {
            separador: ',',
            tem_cabecalho: true,
        }
    }

    fn com_separador(mut self, sep: char) -> Self {
        self.separador = sep;
        self
    }
}

impl ProcessadorArquivo for ProcessadorCsv {
    fn nome_formato(&self) -> &str {
        "CSV"
    }

    fn parsear(&self, conteudo: &str) -> Result<Vec<Registro>, ErroProcessamento> {
        let mut linhas = conteudo.lines();

        // Extrair cabeçalhos
        let cabecalhos: Vec<String> = if self.tem_cabecalho {
            match linhas.next() {
                Some(linha) => linha.split(self.separador)
                    .map(|c| c.trim().to_string())
                    .collect(),
                None => return Err(ErroProcessamento::Parse("Arquivo vazio".to_string())),
            }
        } else {
            // Gerar nomes genéricos
            (0..10).map(|i| format!("coluna_{}", i)).collect()
        };

        // Parsear linhas de dados
        let mut registros = Vec::new();
        for (num_linha, linha) in linhas.enumerate() {
            if linha.trim().is_empty() {
                continue;
            }

            let valores: Vec<&str> = linha.split(self.separador).collect();

            if valores.len() != cabecalhos.len() {
                return Err(ErroProcessamento::Parse(format!(
                    "Linha {}: esperado {} colunas, encontrado {}",
                    num_linha + 2, cabecalhos.len(), valores.len()
                )));
            }

            let mut registro = Registro::novo();
            for (cab, val) in cabecalhos.iter().zip(valores.iter()) {
                registro.adicionar(cab, val.trim());
            }
            registros.push(registro);
        }

        Ok(registros)
    }

    /// Validação específica para CSV: verificar campos não vazios
    fn validar(&self, registros: Vec<Registro>) -> Result<Vec<Registro>, ErroProcessamento> {
        let validos: Vec<Registro> = registros.into_iter()
            .filter(|r| r.campos.iter().all(|(_, v)| !v.is_empty()))
            .collect();
        Ok(validos)
    }
}

// ============================================================
// Implementação: Processador de Pares Chave=Valor
// ============================================================

struct ProcessadorChaveValor {
    separador_par: char,
    separador_registro: char,
}

impl ProcessadorChaveValor {
    fn novo() -> Self {
        ProcessadorChaveValor {
            separador_par: '=',
            separador_registro: '\n',
        }
    }
}

impl ProcessadorArquivo for ProcessadorChaveValor {
    fn nome_formato(&self) -> &str {
        "ChaveValor"
    }

    fn parsear(&self, conteudo: &str) -> Result<Vec<Registro>, ErroProcessamento> {
        let mut registros = Vec::new();
        let mut registro_atual = Registro::novo();
        let mut tem_dados = false;

        for linha in conteudo.lines() {
            let linha = linha.trim();

            // Linha vazia separa registros
            if linha.is_empty() {
                if tem_dados {
                    registros.push(registro_atual);
                    registro_atual = Registro::novo();
                    tem_dados = false;
                }
                continue;
            }

            // Ignorar comentários
            if linha.starts_with('#') {
                continue;
            }

            // Parsear chave=valor
            let partes: Vec<&str> = linha.splitn(2, self.separador_par).collect();
            if partes.len() != 2 {
                return Err(ErroProcessamento::Parse(
                    format!("Formato inválido: '{}'", linha),
                ));
            }

            registro_atual.adicionar(partes[0].trim(), partes[1].trim());
            tem_dados = true;
        }

        // Último registro
        if tem_dados {
            registros.push(registro_atual);
        }

        Ok(registros)
    }

    /// Transformação: normalizar chaves para minúsculas
    fn transformar(&self, registros: Vec<Registro>) -> Result<Vec<Registro>, ErroProcessamento> {
        let transformados = registros.into_iter().map(|r| {
            let mut novo = Registro::novo();
            for (chave, valor) in &r.campos {
                novo.adicionar(&chave.to_lowercase(), valor);
            }
            novo
        }).collect();
        Ok(transformados)
    }

    fn pos_processar(&self, registros: &[Registro]) {
        println!("[ChaveValor] Pós-processamento: {} registros finalizados", registros.len());
    }
}

// ============================================================
// Implementação: Processador de Linhas Fixas
// ============================================================

struct ProcessadorLinhaFixa {
    definicao_campos: Vec<(String, usize, usize)>, // (nome, início, tamanho)
}

impl ProcessadorLinhaFixa {
    fn novo(campos: Vec<(&str, usize, usize)>) -> Self {
        ProcessadorLinhaFixa {
            definicao_campos: campos.into_iter()
                .map(|(n, i, t)| (n.to_string(), i, t))
                .collect(),
        }
    }
}

impl ProcessadorArquivo for ProcessadorLinhaFixa {
    fn nome_formato(&self) -> &str {
        "LinhaFixa"
    }

    fn parsear(&self, conteudo: &str) -> Result<Vec<Registro>, ErroProcessamento> {
        let mut registros = Vec::new();

        for (num_linha, linha) in conteudo.lines().enumerate() {
            if linha.trim().is_empty() {
                continue;
            }

            let mut registro = Registro::novo();

            for (nome, inicio, tamanho) in &self.definicao_campos {
                let fim = inicio + tamanho;
                if fim > linha.len() {
                    return Err(ErroProcessamento::Parse(format!(
                        "Linha {}: campo '{}' excede o tamanho ({}..{}, linha tem {})",
                        num_linha + 1, nome, inicio, fim, linha.len()
                    )));
                }
                let valor = linha[*inicio..fim].trim();
                registro.adicionar(nome, valor);
            }

            registros.push(registro);
        }

        Ok(registros)
    }

    fn pre_processar(&self, conteudo: &str) -> String {
        // Remover linhas de cabeçalho (comum em arquivos de linha fixa)
        conteudo.lines()
            .skip(1) // Pula a primeira linha (cabeçalho)
            .collect::<Vec<&str>>()
            .join("\n")
    }
}

fn main() {
    // ============================================================
    // Processando CSV
    // ============================================================
    println!("{'='repeated 50}");
    println!("Processando CSV");
    println!("{'='repeated 50}");

    let csv = "nome,email,idade\nAlice,alice@ex.com,30\nBob,bob@ex.com,25\nCarol,,28";
    let processador_csv = ProcessadorCsv::novo();
    match processador_csv.processar(csv) {
        Ok(registros) => {
            println!("\nResultado:");
            for r in &registros {
                println!("  {}", r);
            }
        }
        Err(e) => println!("Erro: {}", e),
    }

    // ============================================================
    // Processando Chave=Valor
    // ============================================================
    println!("\n{'='repeated 50}");
    println!("Processando Chave=Valor");
    println!("{'='repeated 50}");

    let kv = "# Configuração do servidor\nHost=localhost\nPorta=8080\nDebug=true\n\nHost=remoto.com\nPorta=443\nDebug=false";
    let processador_kv = ProcessadorChaveValor::novo();
    match processador_kv.processar(kv) {
        Ok(registros) => {
            println!("\nResultado:");
            for r in &registros {
                println!("  {}", r);
            }
        }
        Err(e) => println!("Erro: {}", e),
    }

    // ============================================================
    // Processando Linha Fixa
    // ============================================================
    println!("\n{'='repeated 50}");
    println!("Processando Linha Fixa");
    println!("{'='repeated 50}");

    let fixa = "NOME      CIDADE    IDADE\nAlice     São Paulo 030\nBob       Rio       025";
    let processador_fixa = ProcessadorLinhaFixa::novo(vec![
        ("nome", 0, 10),
        ("cidade", 10, 10),
        ("idade", 20, 3),
    ]);
    match processador_fixa.processar(fixa) {
        Ok(registros) => {
            println!("\nResultado:");
            for r in &registros {
                println!("  {}", r);
            }
        }
        Err(e) => println!("Erro: {}", e),
    }
}
```

## Diagrama

```
    Template Method — Fluxo do Algoritmo:

    trait ProcessadorArquivo {

        fn processar()          ← TEMPLATE METHOD (define o fluxo)
        ┌──────────────────────────────────────────┐
        │  1. pre_processar()   ← hook (default)   │
        │  2. parsear()         ← ABSTRATO (obrig.) │
        │  3. validar()         ← hook (default)   │
        │  4. transformar()     ← hook (default)   │
        │  5. pos_processar()   ← hook (default)   │
        └──────────────────────────────────────────┘

    }

    Implementações:

    ┌───────────────────┐  ┌─────────────────┐  ┌─────────────────┐
    │  ProcessadorCsv   │  │  Processador    │  │  Processador    │
    │                   │  │  ChaveValor     │  │  LinhaFixa      │
    │───────────────────│  │─────────────────│  │─────────────────│
    │ parsear()    ✓    │  │ parsear()   ✓   │  │ parsear()   ✓   │
    │ validar()    ✓    │  │ transformar()✓  │  │ pre_proc.   ✓   │
    │ (customizado)     │  │ pos_proc()  ✓   │  │ (customizado)   │
    │                   │  │ (customizados)  │  │                 │
    │ pre_processar()   │  │ pre_processar() │  │ validar()       │
    │ transformar()     │  │ validar()       │  │ transformar()   │
    │ pos_processar()   │  │ (herdados)      │  │ pos_processar() │
    │ (herdados)        │  │                 │  │ (herdados)      │
    └───────────────────┘  └─────────────────┘  └─────────────────┘

    Pontos de customização:

    ┌──────────────┬────────────────┬───────────────────────────┐
    │ Tipo         │ Obrigatório?   │ Propósito                 │
    ├──────────────┼────────────────┼───────────────────────────┤
    │ parsear()    │ SIM (sem       │ Lógica específica do      │
    │              │ default)       │ formato de arquivo        │
    │──────────────┼────────────────┼───────────────────────────│
    │ pre_proc()   │ NÃO (default)  │ Preparação opcional       │
    │ validar()    │ NÃO (default)  │ Validação opcional        │
    │ transformar()│ NÃO (default)  │ Transformação opcional    │
    │ pos_proc()   │ NÃO (default)  │ Finalização opcional      │
    └──────────────┴────────────────┴───────────────────────────┘
```

## Exemplo do Mundo Real

Um framework de testes simplificado com setup/teardown template:

```rust
/// Resultado de um teste
#[derive(Debug)]
enum ResultadoTeste {
    Passou,
    Falhou(String),
    Pulado(String),
}

impl fmt::Display for ResultadoTeste {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ResultadoTeste::Passou => write!(f, "PASSOU"),
            ResultadoTeste::Falhou(msg) => write!(f, "FALHOU: {}", msg),
            ResultadoTeste::Pulado(msg) => write!(f, "PULADO: {}", msg),
        }
    }
}

/// Trait com Template Method para testes
trait CasoTeste {
    /// Template Method — NÃO sobrescreva
    fn executar(&mut self) -> ResultadoTeste {
        println!("\n--- Teste: {} ---", self.nome());

        // Verificar pré-condição
        if let Some(motivo) = self.pular_se() {
            return ResultadoTeste::Pulado(motivo);
        }

        // Setup
        println!("  [setup]");
        if let Err(e) = self.setup() {
            return ResultadoTeste::Falhou(format!("Falha no setup: {}", e));
        }

        // Execução do teste
        println!("  [executando]");
        let resultado = self.testar();

        // Teardown (sempre executa, mesmo se o teste falhou)
        println!("  [teardown]");
        if let Err(e) = self.teardown() {
            println!("  [AVISO] Falha no teardown: {}", e);
        }

        println!("  [resultado] {}", resultado);
        resultado
    }

    // Pontos de customização
    fn nome(&self) -> &str;
    fn testar(&mut self) -> ResultadoTeste;

    // Hooks opcionais
    fn setup(&mut self) -> Result<(), String> { Ok(()) }
    fn teardown(&mut self) -> Result<(), String> { Ok(()) }
    fn pular_se(&self) -> Option<String> { None }
}

/// Teste concreto: verificar cálculo
struct TesteCalculo {
    resultado: Option<f64>,
}

impl CasoTeste for TesteCalculo {
    fn nome(&self) -> &str { "Cálculo de área do círculo" }

    fn setup(&mut self) -> Result<(), String> {
        self.resultado = None;
        println!("    Inicializando calculadora...");
        Ok(())
    }

    fn testar(&mut self) -> ResultadoTeste {
        let raio = 5.0;
        let area = std::f64::consts::PI * raio * raio;
        self.resultado = Some(area);

        let esperado = 78.5398;
        if (area - esperado).abs() < 0.001 {
            ResultadoTeste::Passou
        } else {
            ResultadoTeste::Falhou(format!(
                "Esperado ~{}, obtido {}", esperado, area
            ))
        }
    }
}

/// Teste concreto: verificar conexão (simulado)
struct TesteConexao {
    conectado: bool,
}

impl CasoTeste for TesteConexao {
    fn nome(&self) -> &str { "Conexão com banco de dados" }

    fn setup(&mut self) -> Result<(), String> {
        println!("    Conectando ao banco...");
        self.conectado = true;
        Ok(())
    }

    fn testar(&mut self) -> ResultadoTeste {
        if self.conectado {
            ResultadoTeste::Passou
        } else {
            ResultadoTeste::Falhou("Não conectado".to_string())
        }
    }

    fn teardown(&mut self) -> Result<(), String> {
        println!("    Desconectando...");
        self.conectado = false;
        Ok(())
    }
}

/// Teste concreto: teste que deve ser pulado
struct TestePulaCondicional;

impl CasoTeste for TestePulaCondicional {
    fn nome(&self) -> &str { "Funcionalidade experimental" }

    fn pular_se(&self) -> Option<String> {
        // Simula uma condição de pulo
        Some("Funcionalidade em desenvolvimento".to_string())
    }

    fn testar(&mut self) -> ResultadoTeste {
        unreachable!("Este teste não deveria executar")
    }
}

/// Runner de testes
fn executar_suite(testes: &mut [Box<dyn CasoTeste>]) {
    let mut passou = 0;
    let mut falhou = 0;
    let mut pulou = 0;

    for teste in testes.iter_mut() {
        match teste.executar() {
            ResultadoTeste::Passou => passou += 1,
            ResultadoTeste::Falhou(_) => falhou += 1,
            ResultadoTeste::Pulado(_) => pulou += 1,
        }
    }

    println!("\n==========================================");
    println!("Resumo: {} passaram, {} falharam, {} pulados",
        passou, falhou, pulou);
    println!("==========================================");
}

fn main() {
    let mut suite: Vec<Box<dyn CasoTeste>> = vec![
        Box::new(TesteCalculo { resultado: None }),
        Box::new(TesteConexao { conectado: false }),
        Box::new(TestePulaCondicional),
    ];

    executar_suite(&mut suite);
}
```

## Quando Usar

- **Algoritmo com passos fixos mas lógica variável**: O fluxo é o mesmo, mas detalhes mudam por formato/tipo
- **Framework / biblioteca**: Definir o esqueleto que usuários customizam
- **Processamento de dados**: ETL (Extract-Transform-Load) com fontes variáveis
- **Testes**: Setup/teardown com lógica de teste customizável
- **Relatórios**: Estrutura fixa (cabeçalho, corpo, rodapé) com conteúdo variável

## Quando NÃO Usar

- **Algoritmo totalmente diferente**: Se os passos mudam entre implementações, não há template a reusar
- **Apenas um passo customizável**: Se só o parsing muda, uma closure ou Strategy é mais simples
- **Muitos pontos de customização**: Se a maioria dos métodos é sobrescrita, a trait se torna uma interface pura (Strategy)
- **Composição preferível**: Se os passos são independentes, compose funções em vez de herdar template

## Variações em Rust

### Template com tipos genéricos associados

```rust
/// Template method com tipo de saída configurável
trait Exportador {
    type Saida;
    type Erro: fmt::Display;

    /// Template method
    fn exportar(&self, dados: &[Registro]) -> Result<Self::Saida, Self::Erro> {
        let filtrados = self.filtrar(dados);
        let formatados = self.formatar(&filtrados)?;
        self.finalizar(formatados)
    }

    fn filtrar<'a>(&self, dados: &'a [Registro]) -> Vec<&'a Registro> {
        dados.iter().collect() // Default: todos os registros
    }

    fn formatar(&self, dados: &[&Registro]) -> Result<Self::Saida, Self::Erro>;
    fn finalizar(&self, saida: Self::Saida) -> Result<Self::Saida, Self::Erro> {
        Ok(saida) // Default: retorna como está
    }
}
```

### Template com closures (mais flexível)

```rust
/// Builder de pipeline com closures configuráveis
struct PipelineProcessamento<T> {
    pre_processamento: Box<dyn Fn(&str) -> String>,
    processamento: Box<dyn Fn(&str) -> Result<Vec<T>, String>>,
    pos_processamento: Box<dyn Fn(Vec<T>) -> Vec<T>>,
}

impl<T> PipelineProcessamento<T> {
    fn novo<F>(processamento: F) -> Self
    where
        F: Fn(&str) -> Result<Vec<T>, String> + 'static,
    {
        PipelineProcessamento {
            pre_processamento: Box::new(|s| s.trim().to_string()),
            processamento: Box::new(processamento),
            pos_processamento: Box::new(|v| v),
        }
    }

    fn com_pre_processamento(mut self, f: impl Fn(&str) -> String + 'static) -> Self {
        self.pre_processamento = Box::new(f);
        self
    }

    fn com_pos_processamento(mut self, f: impl Fn(Vec<T>) -> Vec<T> + 'static) -> Self {
        self.pos_processamento = Box::new(f);
        self
    }

    fn executar(&self, entrada: &str) -> Result<Vec<T>, String> {
        let preparado = (self.pre_processamento)(entrada);
        let resultado = (self.processamento)(&preparado)?;
        Ok((self.pos_processamento)(resultado))
    }
}
```

## Padrões Relacionados

- **[Strategy](/padroes/strategy/)**: Strategy troca o algoritmo inteiro; Template Method troca apenas passos do algoritmo
- **[Factory](/padroes/factory/)**: Factory Methods frequentemente usam Template Method para definir o fluxo de criação
- **[Builder](/padroes/builder/)**: Builder define passos de construção; Template Method define passos de processamento
- **[Chain of Responsibility](/padroes/chain-of-responsibility/)**: Ambos processam em etapas; Chain permite interromper, Template segue o fluxo completo

## Conclusão

O Template Method em Rust se implementa naturalmente com traits e métodos default. A trait define o esqueleto do algoritmo como um método default que chama métodos abstratos (pontos de customização) e hooks (métodos com implementação padrão). O compilador garante que todos os pontos obrigatórios sejam implementados, e os hooks permitem personalização opcional sem código boilerplate. Esta abordagem é mais segura e flexível que herança de classes em OOP, pois evita problemas como o "frágil base class" e permite que um tipo implemente múltiplas traits template simultaneamente.
