Padrões de Projeto · POO · IFAL 2026.1

Strategy
Design Pattern

Encapsulando algoritmos em Java — do if/else à extensão sem atrito

Grupo Eliezir Moreira Thomas Gabriel Carlos Roque Eduardo Pereira
Professor Kenji
Disciplina Programação Orientada a Objetos
Curso Sistemas de Informação · 4º período
Data Abril de 2026
1
Sumário

O que será abordado

  • 01
    O que são padrões de projeto
    Definição, analogias, famílias da GoF
  • 02
    Por que padrões importam
    Linguagem, code review, autodocumentação
  • 03
    Strategy — intenção e problema
    O método gigante e o risco de regressão
  • 04
    Estrutura técnica
    Baseada no Refactoring Guru · composição > herança
  • 05
    Exemplo em Java
    Carrinho de frete · interface → runtime
  • 06
    Prós e contras
    O que ganha e o que paga
  • 07
    Quando aplicar
    Dica de ouro · quando NÃO usar
  • 08
    Mini quiz pro público
    3 perguntas · engajamento + fechamento
2
Bloco 1 · Fundamentos

O que são padrões de projeto

"Soluções reutilizáveis e nomeadas para problemas que aparecem repetidamente no design de sistemas orientados a objetos."

Não é código pronto — é uma receita pra resolver um tipo de problema.

Pra fixar a ideia, três analogias do mundo real. Cada uma mostra uma propriedade diferente do que é um padrão — e no final, tudo volta pra uma ideia só: estrutura nomeada, reutilizada, adaptada ao contexto.

→ próximos três slides

3
Bloco 1 · Analogia 1 de 3 · Receita

A receita é a receita — não o bolo

Bolo de Chocolate
· da Vó Maria · 1952 ·

Ingredientes

  • 3 ovos
  • 2 xícaras de farinha
  • 1 xícara de chocolate em pó

Modo de preparo

  1. Bata as claras em neve
  2. Misture tudo e despeje na forma
  3. Asse por 35 min a 180°C
  • Dois cozinheiros seguindo a mesma receita fazem bolos levemente diferentes — um mais fofo, outro mais denso.
  • Os dois são reconhecidamente "Bolo de Chocolate da Vó Maria".
  • A receita guia, não obriga — cada um adapta ao forno e à ocasião.
O padrão é a receita.
O código que você escreve é o bolo.
4
Bloco 1 · Analogia 2 de 3 · Tiki-taka

Tiki-taka

triangulação — passes curtos

Estilo de jogo onde os jogadores estão constantemente se movendo e tocando a bola entre si.

Em vez de listar 11 posições e uma filosofia de jogo, o treinador fala:

"joga tiki-taka"
Uma palavra, 11 jogadores alinhados.
5
Bloco 1 · Analogia 3 de 3 · Xadrez

"Abertura Italiana" — ou lance-a-lance

♜ ♝ ♛ ♚ ♞ ♜ ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♖ ♘ ♗ ♕ ♔ ♖ ♙ ♟ ♘ ♞ ♗ ♝
Giuoco Piano — 1.e4 e5 · 2.Nf3 Nc6 · 3.Bc4 Bc5

Opção A — lance-a-lance

"Peão-rei avança duas casas, preto espelha. Cavalo-rei sai pra f3 atacando o centro; preto defende com cavalo-dama em c6. Bispo-rei sai pra c4; preto responde com bispo em c5…"

Opção B — o nome

"Abertura Italiana"
Usar o padrão Strategy é a mesma coisa.
6
Bloco 1 · O catálogo

Gang of Four · 23 padrões · 3 famílias

Consagrados em 1994 pelo livro Design Patterns dos quatro autores conhecidos como Gang of Four (GoF): Gamma, Helm, Johnson e Vlissides. Os 23 padrões clássicos se dividem em três grandes famílias segundo o tipo de problema que resolvem.

Criacionais
Como objetos são criados.
Ex.: Singleton, Factory, Builder
Estruturais
Como objetos se compõem.
Ex.: Adapter, Decorator, Facade
Comportamentais
Como objetos colaboram e distribuem responsabilidades.
Ex.: Observer, Strategy, State

Strategy é comportamental — vamos focar nele hoje.

7
Bloco 1 · Cuidados

O que padrão não é

Não é biblioteca
Você não import "Strategy" de lugar nenhum. Padrão é código que você escreve — não dependência que você adiciona.
Não é framework
Padrão é independente de Spring, Quarkus, qualquer stack. Funciona igual em Java, Python, Kotlin, TypeScript.
Não é obrigação
Usar padrão em código que não precisa é over-engineering. Padrão existe pra resolver dor — sem dor, só custo.
É vocabulário compartilhado
Dizer "aqui é Strategy" faz qualquer dev experiente entender a estrutura em 3 segundos. Esse é o verdadeiro valor.
8
Bloco 2 · Colaboração humana

Por que padrões importam

Em qualquer projeto real, você passa mais tempo lendo código do que escrevendo.

Linguagem onipresente
"Aqui usamos Strategy" resume, em 1 frase, o que levaria minutos pra explicar. Igual dizer "Siciliana" em xadrez ou "4-4-2" em futebol.
Code review & onboarding
O revisor já sabe a estrutura — foca na lógica, não na forma. Dev novo entende a feature em segundos, não horas.
Código autodocumentado
A estrutura revela a intenção do autor. Seis meses depois, quando ninguém lembra por que, o padrão continua comunicando.

Padrão é, antes de tudo, uma decisão social dentro de um time de engenharia.

9
Bloco 2 · Frase-chave

Frameworks mudam.
Padrões persistem.

Spring muda, Quarkus muda, o próprio Java muda. Mas o conceito de "encapsular algoritmo em uma classe que implementa uma interface comum" é verdade em 1994, em 2026, e vai ser em 2040.

10
Bloco 3 · Strategy · Intenção

O padrão Strategy — comportamental

"Define uma família de algoritmos, encapsula cada um e os torna intercambiáveis. Strategy permite que o algoritmo varie independentemente dos clientes que o usam."

Gamma, Helm, Johnson & Vlissides · Design Patterns (1994)

Em linguagem humana: quando você tem várias formas de fazer a mesma coisa, cada forma vira uma classe separada, e o código que usa escolhe qual usar sem saber os detalhes.

Comportamental = foca em como objetos colaboram, não em como são criados ou compostos.

11
Bloco 3 · O problema — o método gigante
public class CalculadoraFrete {

    public double calcular(String transp, double pesoKg, Endereco dest) {
        if (transp.equals("CORREIOS")) {
            correios.connect();
            correios.authenticate(config.getCorreiosKey());
            Cotacao c = correios.cotar(pesoKg, dest.getCep());
            correios.disconnect();
            metrics.increment("frete.correios");
            return c.getValor();
        } else if (transp.equals("JADLOG")) {
            JadlogResponse r = jadlog.cotar(pesoKg, dest);
            if (r.isFailed()) retry(transp, pesoKg, dest);
            return r.getValor();
        } else if (transp.equals("LOGGI")) {
            String token = config.getLoggiToken();
            if (token == null) throw new IllegalStateException("sem token Loggi");
            return loggi.calcular(token, pesoKg, dest);
        } else if (transp.equals("MERCADO_ENVIOS")) {
            Long sellerId = user.getMercadoLivreId();
            return mercadoEnvios.cotar(sellerId, pesoKg, dest);
        } else if (transp.equals("RETIRADA")) {
            // adicionado na sprint passada
            return 0.0;
        } else if (transp.equals("DRONE")) {
            // adicionado ontem — o time comercial pediu
            return drone.calcular(dest.getCoords(), pesoKg);
        }
        throw new IllegalArgumentException("Transportadora: " + transp);
    }
}
Dispatch por string. O próprio tipo do parâmetro já é o sinal de alarme — a lógica depende de comparar texto com o nome da transportadora.
CORREIOS — o ciclo de vida da API vaza pra cá. Connect, auth, cotar, disconnect, métricas. Seis responsabilidades num bloco de negócio.
JADLOG — estilo totalmente diferente. API síncrona com retorno tipado, lógica de retry inline. Cada integração impõe o seu jeito.
LOGGI — null-check virou regra de negócio. Erro de infraestrutura (token ausente) vazando como exceção pro chamador.
MERCADO_ENVIOS — mais uma API, mais um identificador. Agora tem sellerId em Long. Cada nova transportadora traz um vocabulário próprio.
"adicionado na sprint passada". Comentário honesto — é assim que if/else hell nasce: uma transportadora por vez.
"adicionado ontem". E o ciclo continua. A cada sprint, um frete novo no mesmo arquivo, com o mesmo dono que vira gargalo.
Fallback por exceção. Se alguém digitar "correios" minúsculo, boom em produção. Sem teste unitário dá pra perceber?
12
Bloco 3 · Os cinco problemas

Por que esse código é problemático?

Strings mágicas
Um "correios" em minúsculo quebra silenciosamente — o compilador não avisa.
Viola o OCP
Cada nova transportadora exige editar esta classe. Aberto pra extensão? Fechado pra modificação? Nenhum dos dois.
⚠ Risco de regressão — o mais perigoso
Adicionar a próxima transportadora exige mexer no mesmo método que já tem o cálculo da Jadlog homologado em produção há meses. Um else no lugar errado, um refactor mal pensado, e você quebra uma funcionalidade que estava funcionando. No mundo real: bug em produção, ticket aberto, rollback de madrugada.
Lógica acoplada
Testar o cálculo da Jadlog exige instanciar CalculadoraFrete inteira — com todas as dependências.
Cresce pra sempre
3 casos hoje, 7 no ano que vem, 15 em dois anos — o clássico if/else hell.
13
Bloco 3 · A solução

Encapsular cada algoritmo numa classe própria

Antes
class CalculadoraFrete {
  calcular(tipo, peso) {
    if (tipo == "CORREIOS") ...
    if (tipo == "JADLOG")   ...
    if (tipo == "RETIRADA") ...
    // (15 ifs depois)
  }
}
Depois
class Carrinho { FreteStrategy frete; }

interface FreteStrategy { calcular(peso); }

class FreteCorreios  implements FreteStrategy { ... }
class FreteJadlog    implements FreteStrategy { ... }
class FreteRetirada  implements FreteStrategy { ... }
  • Adicionar Loggi amanhã = uma classe nova. Zero alteração no Carrinho.
  • Testar isolado: new FreteJadlog().calcular(2.0). Sem montar sistema inteiro.
  • O Carrinho não conhece as implementações — só a interface.
14
Bloco 4 · Estrutura · baseada no Refactoring Guru

Os quatro atores do padrão

Context Carrinho
«interface» Strategy
concreteStrategy A
concreteStrategy B
concreteStrategy C
  • Contexto — classe que precisa do algoritmo. Não sabe como, apenas quando executar. Guarda referência e delega.
  • Interface Strategy — o contrato que todas as estratégias seguem. Um método (ou poucos).
  • Estratégias Concretas — cada algoritmo numa classe própria, implementando o contrato.
  • Cliente — quem configura qual estratégia o Contexto usa. Escolhe e injeta.

Fluxo: Cliente escolhe → injeta no Context → Context chama strategy.execute() sem saber qual é → pra trocar em runtime, passa outra instância.

15
Bloco 4 · Princípio de design

Prefira composição em vez de herança

Strategy é a aplicação prática de um dos princípios mais clássicos do GoF. Herança amarra o comportamento à identidade da classe em tempo de compilação. Composição pluga comportamento em runtime.

Com herança — is-a
class CarrinhoCorreios
    extends CalculadoraCorreios {
  // preso a Correios
  // em tempo de compilação
}

class CarrinhoJadlog
    extends CalculadoraJadlog { ... }
Pra trocar de transportadora → outra subclasse. Explosão combinatória se mais de um eixo variar.
Com composição — has-a
class Carrinho {
  FreteStrategy frete;
  // tem-um FreteStrategy
  // plugado em runtime
}

carrinho.setFrete(new FreteLoggi());
Um Carrinho, N estratégias plugáveis. Trocar em runtime é setFrete(...).

Herança amarra. Composição liberta.

16
Bloco 4 · Essência

Strategy é polimorfismo com nome e intenção

Muita gente aprende polimorfismo em POO e depois aprende Strategy, e pensa "mas isso é só polimorfismo". É — mas com uma intenção nomeada.

O valor do padrão é comunicar: quando você diz FreteStrategy, qualquer leitor sabe imediatamente por que o polimorfismo está sendo usado ali.

17
Bloco 5 · Passo 1 de 5

A interface — o contrato

strategy
public interface FreteStrategy {
    double calcular(double pesoKg);
}
  • Um único método — define o contrato que toda estratégia de frete precisa implementar.
  • É o ponto de desacoplamento entre quem usa o frete e quem calcula.
  • Tão simples que Java a trata como functional interface — volta mais tarde.
18
Bloco 5 · Passo 2 de 5

Três estratégias, três classes

concrete
public class FreteCorreios
        implements FreteStrategy {

    @Override
    public double calcular(
            double pesoKg) {
        return pesoKg * 2.5
             + 10.0;
    }
}
concrete
public class FreteJadlog
        implements FreteStrategy {

    @Override
    public double calcular(
            double pesoKg) {
        return pesoKg * 3.0
             + 5.0;
    }
}
concrete
public class FreteRetirada
        implements FreteStrategy {

    @Override
    public double calcular(
            double pesoKg) {
        return 0.0;
    }
}

Cada classe cuida apenas da sua regra. O tipo é a classe — sem strings mágicas. E cada uma é testável isolada: new FreteJadlog().calcular(2.0) → 11.0.

19
Bloco 5 · Passo 3 de 5 · Proteção contra null

O Context — Carrinho

context
import java.util.Objects;

public class Carrinho {

    private FreteStrategy frete;

    public Carrinho(FreteStrategy frete) {
        this.frete = Objects.requireNonNull(frete,
            "Estratégia de frete é obrigatória");
    }

    public void setFrete(FreteStrategy frete) {
        this.frete = Objects.requireNonNull(frete,
            "Estratégia de frete é obrigatória");
    }

    public double totalComFrete(double subtotal, double pesoKg) {
        return subtotal + frete.calcular(pesoKg);
    }
}
  • Carrinho só conhece a interface — nunca as classes concretas.
  • Injeção de dependência na veia, sem framework.
  • setFrete permite trocar em runtime.
Por que requireNonNull?
Sem ele, totalComFrete() num carrinho sem estratégia derruba a app com NPE de stack inútil. Com ele, falha rápido, com mensagem clara, no momento da injeção. O Carrinho não existe sem frete.
20
Bloco 5 · Alternativa elegante · Null Object

Null Object — uma "estratégia padrão" que não quebra

Em vez de rejeitar null, você pode criar uma estratégia neutra que representa "nenhum frete". O sistema nunca quebra por ausência de estratégia.

null object
public class FreteIndefinido
        implements FreteStrategy {

    @Override
    public double calcular(double pesoKg) {
        return 0.0;
        // ou lançar exceção de negócio descritiva
    }
}

// No Carrinho, construtor sem args vira válido:
public Carrinho() {
    this.frete = new FreteIndefinido();
}
Fail-fast (slide anterior)
Quebra cedo, mensagem clara. Escolha explícita é obrigatória.
Null Object
Sistema continua rodando. "Nada" é um estado válido.

Em frete, a regra exige escolha explícita → fail-fast. Em logger que pode estar desabilitado → Null Object.

21
Bloco 5 · Passo 4 de 5

Troca em runtime

main
public class App {
    public static void main(String[] args) {
        Carrinho carrinho = new Carrinho(new FreteCorreios());
        System.out.println(carrinho.totalComFrete(100.0, 2.0));

        carrinho.setFrete(new FreteJadlog());
        System.out.println(carrinho.totalComFrete(100.0, 2.0));

        carrinho.setFrete(new FreteRetirada());
        System.out.println(carrinho.totalComFrete(100.0, 2.0));
    }
}
output
$ java App 115.0 // Correios (2kg) 111.0 // Jadlog (2kg) 100.0 // Retirada (grátis)

Adicionar Loggi amanhã? FreteLoggi implements FreteStrategy. Zero alteração no Carrinho — OCP na prática.

22
Bloco 5 · Bônus · se sobrar tempo

Java moderno — lambda como Strategy

java 8+
// FreteStrategy tem 1 método só
// → é uma functional interface

FreteStrategy freteGratis =
    peso -> 0.0;

FreteStrategy fretePromocional =
    peso -> peso * 1.0;

carrinho.setFrete(freteGratis);

Padrão não envelhece — a linguagem evolui pra expressá-lo melhor.

Estratégias pequenas, de escopo local, podem virar uma linha. O padrão continua lá — só mudou a sintaxe. Nasceu em 1994, Java 8 de 2014 expressa melhor.

23
Bloco 6 · Trade-offs

Prós e contras

Prós
  • Troca em runtime — muda o algoritmo sem recompilar o cliente.
  • Isolamento — cada algoritmo numa classe pequena e focada.
  • Testes triviais — new FreteJadlog().calcular(2.0), sem montar sistema.
  • Extensão sem modificação — OCP na prática, sem risco de regressão.
Contras
  • Mais arquivos — 1 interface + N classes em vez de 1 classe com if/else.
  • Cliente precisa saber escolher — alguém decide qual estratégia usar (daí Factory às vezes vir junto).
  • Over-engineering em domínio estável — 2 algoritmos que nunca vão virar 5 custam mais do que entregam.
Comparação — sem Strategy: 2 arquivos (CalculadoraFrete.java + Main.java) · com Strategy: 7 arquivos (FreteStrategy + 4 concretas + Carrinho + Main)
o preço da extensibilidade
De 2 arquivos para 7 arquivos. O custo é número de classes; o ganho é estender sem tocar no que já roda.
24
Bloco 7 · Quando aplicar

Use Strategy quando…

  • Você tem várias variantes de um algoritmo que precisam ser trocadas.
  • Essas variantes tendem a crescer ao longo do tempo.
  • Você quer isolar a lógica complexa da classe principal de negócio.
  • Você quer testar cada variante isoladamente.

Dica de ouro

"Se você se pegar escrevendo switch ou vários if/else baseados em tipos de comportamento — é hora de considerar Strategy."

25
Bloco 7 · Armadilhas

Quando não usar Strategy

Over-engineering
2 casos que nunca vão virar 5? Um if/else simples é mais honesto que interface + 2 classes.
Abstração vazia
Se todas as "estratégias" fazem quase a mesma coisa, você não está usando Strategy — está usando interface pra constar.
Dogma
Padrão é decisão de design, não obrigação. O padrão serve o projeto — não o contrário.

Use padrões pra problemas que doem. Código simples que nunca cresce é ok ser simples.

26
Bloco 8 · Mini quiz · Pergunta 1 de 2

Em qual desses códigos Strategy resolve o problema?

ACódigo A
double calcular(String tipo, double peso) {
  if (tipo.equals("CORREIOS")) return peso*2.5+10;
  if (tipo.equals("JADLOG"))   return peso*3.0+5;
  if (tipo.equals("RETIRADA")) return 0;
}
BCódigo B
void processar(Pedido p) {
  if (p.estado == PENDENTE) aguardar(p);
  if (p.estado == PAGO)      separar(p);
  if (p.estado == ENVIADO)   entregar(p);
}
CCódigo C
void salvar(Usuario u) {
  if (u.nome  == null) throw new Erro();
  if (u.email == null) throw new Erro();
  if (u.idade < 18)   throw new Erro();
  repo.save(u);
}
DCódigo D
void onPedidoCriado(Pedido p) {
  email.enviar(p);
  estoque.reservar(p);
  analytics.track(p);
  auditLog.registrar(p);
}
Clique em um código e envie sua resposta.
Correto! No Código A temos várias formas de fazer a mesma coisa — cálculo de frete por transportadora. Cada variação vira uma classe que implementa FreteStrategy.   B é State (ciclo de vida), C é validação em cadeia (guard clauses bastam), D pede Observer.
A resposta é Código A — lá há várias formas de fazer a mesma coisa, que é exatamente o que Strategy encapsula.   B é State (estados do ciclo de vida), C é só validação simples, D pede Observer (notificar vários interessados do mesmo evento).
27
Bloco 8 · Mini quiz · Pergunta 2 de 2

Em qual desses cenários vale a pena aplicar Strategy?

ACenário A
Script de fim de semana
Uma ferramenta de 200 linhas que converte CSV em JSON. Rodou uma vez no trabalho da faculdade, nunca mais vai ser tocada.
BCenário B
Regra que nunca muda
Cálculo de imposto definido por lei há 15 anos. Dois casos: pessoa física e jurídica — e nada indica que vá mudar.
CCenário C
E-commerce em crescimento
3 métodos de pagamento hoje (Pix, cartão, boleto). O produto pediu pra adicionar PayPal, cripto e parcelamento customizado nos próximos meses.
DCenário D
Diferença trivial
Formatar preço como R$ 100,00 ou $ 100.00. Duas moedas, praticamente a mesma lógica — trocar vírgula por ponto.
Escolha o cenário em que Strategy realmente compensa.
Correto! O Cenário C é o caso clássico — variações que tendem a crescer e cada forma encapsulada numa classe torna a extensão trivial.   A é over-engineering em script descartável, B tem regra estável (um if/else basta), D é abstração vazia com variação trivial.
A resposta é Cenário C — Strategy compensa quando as variações tendem a crescer, como métodos de pagamento num e-commerce em expansão.   A é over-engineering pra script descartável, B tem regra estável (não precisa abstrair), D é variação trivial (interface pra constar).
28
Bloco 9 · Conclusão

Strategy em três frases

  • 01
    O que é
    Strategy encapsula variações de um algoritmo em classes separadas, trocáveis em tempo de execução.
  • 02
    Quando usar
    Quando há várias formas de fazer a mesma coisa e elas tendem a crescer ao longo do tempo.
  • 03
    Por que importa
    Código padronizado comunica intenção, encurta code review, acelera onboarding — e padrões persistem mesmo quando frameworks mudam.
29
Q&A

Perguntas?

Sobre Strategy, sobre a demo de frete, sobre o quiz — ou sobre qualquer coisa que ficou na cabeça durante a apresentação.

30

Obrigado!

Eliezir Moreira
Thomas Gabriel
Carlos Roque
Eduardo Pereira
POO · IFAL 2026.1 · Prof. Kenji
32
🎉 🥳 🎊
Parabéns, Kenji!
Feliz Aniversário, Professor!! 🙌
Sumário
Abertura
1 · Capa 2 · Sumário
Bloco 1 — Padrões de projeto
3 · Definição 4 · Analogia 1 · Receita 5 · Analogia 2 · Tiki-taka 6 · Analogia 3 · Xadrez 7 · GoF · 23 padrões · 3 famílias 8 · O que padrão NÃO é
Bloco 2 — Por que importam
9 · Três pilares 10 · Frameworks vs padrões
Bloco 3 — Strategy · intenção
11 · Definição (comportamental) 12 · O método gigante 13 · Problemas + regressão 14 · A solução encapsulada
Bloco 4 — Estrutura
15 · UML + 4 atores 16 · Composição > herança 17 · Polimorfismo com intenção
Bloco 5 — Java
18 · Passo 1: Interface 19 · Passo 2: Concretas 20 · Passo 3: Context (requireNonNull) 21 · Null Object 22 · Passo 4: Runtime + output 23 · Bônus: lambda
Bloco 6 a 8 — Fechamento
24 · Prós e contras 25 · Quando aplicar 26 · Quando NÃO usar 27 · Quiz Q1 — Strategy resolve? 28 · Quiz Q2 — Quando usar?
Encerramento
29 · Conclusão (3 frases) 30 · Perguntas? 31 · Recomendações 32 · Obrigado!