Você já copiou e colou uma lógica parecida em várias classes e pensou: “Tem algo errado aqui”? Em um app iOS, na terceira cópia do código de carregamento de dados específico de uma tela, sua mão começa a hesitar.
É exatamente aí que o padrão Template Method entra em cena.
Em resumo, esse padrão fixa o fluxo completo — a estrutura — em um único lugar e deixa cada implementação preencher apenas as etapas que variam. No Swift, uma extensão de protocolo faz isso de forma muito mais limpa do que a herança.
Neste artigo, vamos ver o que é o padrão Template Method, por que extensões de protocolo chegam perto de ser a solução ideal no Swift e como criar a estrutura com código real.
Vamos começar pelo resumo dos pontos principais
- O padrão Template Method separa um “procedimento fixo + etapas substituíveis”
- Tradicionalmente, ele é implementado por herança de uma classe pai, mas no Swift uma extensão de protocolo é mais adequada
- Coloque a estrutura na implementação padrão da extensão e deixe as partes variáveis como requisitos do protocolo
- Você se livra das limitações da herança, como herança única e alto acoplamento
O que é o padrão Template Method?
O nome parece pomposo, mas o conceito é simples.
Pense em uma receita. A sequência “preparar os ingredientes → preparar → cozinhar → montar o prato” é fixa.
Mas os ingredientes e a forma de cozinhar mudam de prato para prato.
Nesse caso, a sequência — a estrutura — é o Template Method, e cada etapa que muda conforme o prato é a parte substituível.
Controle o fluxo em um único lugar e delegue apenas os detalhes da implementação para fora.
Essa frase praticamente resume todo o padrão Template Method.
No código, a situação é esta. O procedimento de carregamento de dados é igual em qualquer tela: iniciar carregamento → requisição → parsing → atualizar a tela.
O que muda é apenas “qual URL solicitar” e “como fazer o parsing dos dados recebidos”.
Reescrever esse procedimento comum toda vez era desperdício.
Por que usar uma extensão de protocolo no Swift em vez de herança?
A abordagem original coloca a estrutura em uma classe pai e faz as filhas sobrescreverem métodos específicos. É aquele modelo dos livros de Java.
Mas implementar isso por herança de classes no Swift traz várias limitações.
- Classes permitem apenas herança única. Se você já usa uma classe pai, acabou
- Não dá para usar com structs nem enums
- Pai e filho ficam fortemente acoplados, dificultando substituições posteriores
Extensões de protocolo resolvem a maior parte desses problemas.
Forneça o método estrutural como implementação padrão da extensão e declare as etapas variáveis apenas como requisitos do protocolo.
Assim, seja struct ou class, basta adotar o protocolo para receber a estrutura comum gratuitamente, sem as limitações da herança.
Este é um exemplo de como definir o procedimento de carregamento de dados com um protocolo. load() é a estrutura fixa, e os outros dois são as partes substituíveis.
protocol DataLoadable {
associatedtype Item
var endpoint: URL { get } // Diferente em cada tela
func parse(_ data: Data) -> [Item] // Diferente em cada tela
}
extension DataLoadable {
func load() async throws -> [Item] { // Estrutura fixa
let (data, _) = try await URLSession.shared.data(from: endpoint)
return parse(data)
}
}
A extensão controla a ordem de load().
Cada tela só precisa preencher endpoint e parse do seu próprio jeito.
Vamos preencher a estrutura na prática
Agora vamos ver quem adota esse protocolo. Como é adoção, não herança, também pode ser um struct.
struct ArticleLoader: DataLoadable {
let endpoint = URL(string: "https://api.example.com/articles")!
func parse(_ data: Data) -> [Article] {
(try? JSONDecoder().decode([Article].self, from: data)) ?? []
}
}
// Uso: let articles = try await ArticleLoader().load()
Como você pode ver, ArticleLoader não implementa load() diretamente.
Mesmo assim, ele pode chamar load() porque a extensão fornece a implementação padrão.
Esse é o poder de um Template Method criado com uma extensão de protocolo. Quando surgir uma nova tela, basta criar mais um struct que implemente apenas endpoint e parse.
Depois que mudei para essa abordagem, reduzi para menos da metade o código de adicionar telas. Com a lógica de carregamento e tratamento de erros centralizada, corrigir bugs também ficou muito mais fácil.
Um ponto de atenção: a implementação padrão de uma extensão de protocolo funciona de forma um pouco diferente de override. Mesmo que o tipo adotante defina um método com o mesmo nome, se ele não estiver declarado como requisito do protocolo, o despacho estático pode chamar uma implementação inesperada.
Por isso, é mais seguro declarar as etapas substituíveis como requisitos no corpo do protocolo.
Um Q&A rápido para resumir
P. Então não precisamos mais usar Template Method baseado em herança?
Em locais que já têm uma hierarquia de classes, como UIKit, fazer override por herança pode ser natural. Escolha conforme a situação.
P. associatedtype parece complicado.
Se o tipo de retorno for fixo, você pode usar um protocolo comum sem associatedtype. Use-o apenas quando precisar de genéricos.
Quando você cria a estrutura com uma extensão de protocolo, tudo fica tão organizado que a dificuldade anterior com herança chega a parecer desnecessária.
Se existe uma lógica que você continua copiando e colando, extraia hoje apenas uma parte para um protocolo. Você vai entender rapidamente. Boa sorte!

