Pular para o conteúdo
GoF Padrões de Projeto Comportamentais
Comportamental escopo de objeto
GoF, p. 315 também chamado de Policy

Estratégia

Strategy

Vários algoritmos intercambiáveis para a mesma tarefa, escolhidos em tempo de execução.

Complexidade simples Frequência de uso muito comum
Intençãocomo o livro define

Definir uma família de algoritmos, encapsular cada um deles e torná-los intercambiáveis. Strategy permite que o algoritmo varie independentemente dos clientes que o utilizam.

Analogiauma imagem do mundo real

O aplicativo de rotas

Origem e destino são os mesmos; o que muda é como chegar: de carro, a pé, de bicicleta ou de transporte público. Cada modo é um algoritmo completo de cálculo de rota. O app não mudou — você trocou a estratégia com um toque.

O problema

Uma classe acumula várias formas de fazer a mesma coisa. Ela cresce a cada nova variação, os conflitos de merge se multiplicam, e mudanças em um algoritmo arriscam quebrar os outros porque tudo vive no mesmo arquivo.

A solução

Extraia cada algoritmo para sua própria classe, todas implementando a mesma interface. O Context guarda uma referência a uma estratégia e delega, sem saber qual é. Quem escolhe é o cliente.

Sintomascomo reconhecer no seu código
  • if (tipoDeFrete === "sedex") … else if … dentro da regra de negócio.
  • Uma classe com métodos calcularA, calcularB, calcularC quase idênticos.

Estrutura

delegaescolheClientCarrinho (Context)- estrategia+ setEstrategia(s)+ total()«interface»Frete+ calcular(peso, cep)SedexPacRetirada
Fig. 21 — Strategy herda / implementa cria usa / contém
Ver este diagrama sendo desenhado, traço a traço
Participantes
Strategy
Interface comum a todos os algoritmos.
ConcreteStrategy
Uma implementação específica do algoritmo.
Context
Guarda a estratégia atual e delega; expõe um setter para trocá-la.
Client
Escolhe a estratégia concreta e injeta no contexto.

Implementação

Listagem 21 Cálculo de frete: estratégias trocáveis em tempo de execução
// ── Estratégias: cada algoritmo isolado e testável ────
class Frete { calcular(peso, distancia) { throw new Error('abstrato'); } }

class Sedex    extends Frete { calcular(p, d) { return 12 + p * 2.5 + d * 0.08; } }
class Pac      extends Frete { calcular(p, d) { return  6 + p * 1.2 + d * 0.03; } }
class Retirada extends Frete { calcular()     { return 0; } }
class FreteGratisAcimaDe extends Frete {
  constructor(limite, base) { super(); this.limite = limite; this.base = base; }
  calcular(p, d, subtotal) { return subtotal >= this.limite ? 0 : this.base.calcular(p, d); }
}

// ── Context: não sabe COMO se calcula frete ───────────
class Carrinho {
  itens = []; peso = 0;
  constructor(estrategia) { this.estrategia = estrategia; }
  setEstrategia(e) { this.estrategia = e; }        // troca a quente

  adicionar(nome, preco, peso) { this.itens.push({ nome, preco }); this.peso += peso; }
  get subtotal() { return this.itens.reduce((s, i) => s + i.preco, 0); }
  get total()    { return this.subtotal + this.estrategia.calcular(this.peso, 400, this.subtotal); }
}

const carrinho = new Carrinho(new Pac());
carrinho.adicionar('Livro GoF', 180, 1.2);
carrinho.adicionar('Caneca', 45, 0.4);

console.log(carrinho.total.toFixed(2));                    // PAC
carrinho.setEstrategia(new Sedex());
console.log(carrinho.total.toFixed(2));                    // SEDEX
carrinho.setEstrategia(new FreteGratisAcimaDe(200, new Sedex()));
console.log(carrinho.total.toFixed(2));                    // 225.00 — frete zerado

// 💡 Em JavaScript, uma estratégia costuma ser só uma função:
const estrategias = { sedex: (p, d) => 12 + p * 2.5 + d * 0.08, retirada: () => 0 };
// carrinho.estrategia = { calcular: estrategias.sedex };
Na práticaonde ele já existe
  • java.util.Comparator — a estratégia de ordenação
  • javax.servlet.http.HttpServlet#service
  • Estratégias de autenticação do Passport.js; políticas de retry e de cache

Consequências

A favor
  • Troca algoritmos em tempo de execução.
  • Isola implementação de uso; cada algoritmo é testável isoladamente.
  • Substitui herança por composição.
  • Novos algoritmos entram sem tocar no contexto (Aberto/Fechado).
Contra
  • O cliente precisa conhecer as diferenças entre as estratégias para escolher.
  • Exagero se os algoritmos raramente mudam.
  • Em linguagens com funções de primeira classe, classes inteiras podem ser cerimônia desnecessária.
Use quando
  • Você tem muitas variantes de um mesmo algoritmo e quer trocá-las em tempo de execução.
  • Há classes parecidas que só diferem no jeito de executar algo.
  • Você quer esconder do resto do código estruturas de dados e detalhes de um algoritmo.
  • Um `switch` seleciona entre variantes do mesmo comportamento.
Evite quando
  • Existem duas variantes estáveis e simples.

Relações com outros padrões

parecido / fácil de confundir
State
State é Strategy cujas variantes conhecem umas às outras e trocam a si mesmas.
Bridge
Mesma estrutura; Bridge separa dimensões estruturais, Strategy intercambia algoritmos.
Decorator
Decorator muda a pele do objeto; Strategy muda as tripas.
Command
Command encapsula uma AÇÃO a executar; Strategy, um MODO de fazer algo.
alternativa a
Template Method
Template Method varia por HERANÇA (em tempo de compilação, parte do algoritmo); Strategy varia por COMPOSIÇÃO (em tempo de execução, o algoritmo inteiro).
costuma andar junto
Flyweight
Estratégias sem estado podem ser instâncias únicas compartilhadas.

Verificação

Questãoa resposta está marcada

Template Method e Strategy resolvem problemas parecidos. A diferença estrutural é:

  1. Template Method usa herança e varia PARTES do algoritmo; Strategy usa composição e troca o algoritmo INTEIRO em tempo de execução
  2. Strategy só funciona com algoritmos matemáticos
  3. Template Method não permite mais de duas subclasses
  4. Strategy exige que o contexto seja um Singleton

Template Method fixa o esqueleto na superclasse e deixa buracos para as subclasses. Strategy delega tudo a um objeto trocável.