DEV Community

Bruno Souza
Bruno Souza

Posted on

Bora falar do padrão Strategy?

Se você já se pegou pensando “putz, esse if/else aqui tá crescendo demais” ou “cada nova regra quebra algo que já funcionava”, é bem provável que o padrão Strategy seja exatamente o que você está procurando.

Neste post, vamos falar:

  • O que é o Strategy
  • Qual problema ele resolve
  • Quando usar (e quando NÃO usar)
  • Exemplos práticos

O problema clássico

Imagine um sistema que precisa executar uma ação de formas diferentes dependendo do contexto:

  • Tipos diferentes de cálculo
  • Regras que mudam por ambiente (QA, prod)
  • Variações de comportamento por cliente, país ou feature

O caminho mais comum (e perigoso) costuma ser algo assim:

if tipo == A {
  faz isso
} else if tipo == B {
  faz aquilo
} else if tipo == C {
  faz outra coisa
}
Enter fullscreen mode Exit fullscreen mode

Funciona? Funciona.
Escala? Nem um pouco 😅

Cada nova regra:

  • aumenta a complexidade
  • quebra o princípio aberto/fechado (Open/Closed)
  • transforma a função num monstro difícil de testar

O que é o padrão Strategy

O Strategy é um padrão de projeto comportamental que resolve exatamente esse problema.

A ideia central é simples:

Encapsular comportamentos intercambiáveis atrás de uma interface comum

Ou seja:

  • você define o que precisa ser feito (interface)
  • cria várias formas de fazer isso (strategies)
  • escolhe qual usar em tempo de execução

Sem if/else espalhado.
Sem acoplamento desnecessário.


Estrutura do Strategy

Conceitualmente, temos três peças:

  1. Strategy (interface) – define o contrato
  2. Concrete Strategies – implementações do comportamento
  3. Context – quem usa a strategy

Visualmente:

Context -> Strategy
              ↑
   -------------------------
   |           |           |
StrategyA  StrategyB  StrategyC
Enter fullscreen mode Exit fullscreen mode

Exemplo prático

Vamos imaginar um cenário simples:
cálculo de taxa.

Interface

type TaxStrategy interface {
    Calculate(value float64) float64
}
Enter fullscreen mode Exit fullscreen mode

Implementações

type BrazilTax struct{}

func (b *BrazilTax) Calculate(value float64) float64 {
    return value * 0.15
}
Enter fullscreen mode Exit fullscreen mode
type USATax struct{}

func (u *USATax) Calculate(value float64) float64 {
    return value * 0.08
}
Enter fullscreen mode Exit fullscreen mode

Context

type Order struct {
    Tax TaxStrategy
}

func (o *Order) FinalValue(value float64) float64 {
    return value + o.Tax.Calculate(value)
}
Enter fullscreen mode Exit fullscreen mode

Uso

order := Order{Tax: &BrazilTax{}}
final := order.FinalValue(100)
Enter fullscreen mode Exit fullscreen mode

Trocar a regra não exige mudar o Order.
Só trocar a strategy.


Registry de strategies

Em sistemas maiores, é comum usar um registry para centralizar as strategies disponíveis:

var registry = map[string]TaxStrategy{
    "br": &BrazilTax{},
    "us": &USATax{},
}
Enter fullscreen mode Exit fullscreen mode

Isso facilita:

  • extensão do sistema
  • leitura do código
  • configuração por ambiente ou feature

Quando usar Strategy

Use Strategy quando:

✅ Você tem variações de comportamento
✅ Essas variações crescem com o tempo
✅ Você quer eliminar if/else baseados em tipo, regra ou contexto
✅ Testabilidade é importante


Quando NÃO usar

Nem tudo precisa de Strategy 👀

Evite quando:

❌ Existe só uma implementação e nenhuma chance real de variação
❌ A abstração adiciona mais complexidade do que resolve
❌ O comportamento nunca muda

Padrão de projeto não é troféu — é ferramenta.


Erro comum ao usar Strategy

Um erro clássico é deixar a strategy conhecer o contexto errado, como ambiente:

if env == "qa" {
   // lógica especial
}
Enter fullscreen mode Exit fullscreen mode

Se isso começa a aparecer, é sinal de que:

  • você precisa de strategies diferentes
  • ou de comportamentos injetáveis

Strategy boa é pura e focada em uma única responsabilidade.


Conclusão

O padrão Strategy é um dos padrões mais úteis no dia a dia, especialmente em sistemas que:

  • evoluem rápido
  • têm regras de negócio mutáveis
  • precisam ser fáceis de testar e manter

Se você sente que seu código está virando uma árvore de if/else, talvez não seja falta de esforço

Talvez só esteja faltando uma boa Estratégia 😉

Top comments (0)