Padrão Strategy
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 69 de 87.
O Strategy Pattern é um padrão de projeto comportamental que permite definir uma família de algoritmos, encapsular cada um em sua própria classe e torná-los intercambiáveis. Em vez de codificar rigidamente um comportamento específico, você pode trocar os algoritmos em tempo de execução sem alterar o código que os utiliza.
Imagine um sistema de pagamento que suporte múltiplos métodos de pagamento. Sem o Padrão Strategy, você acabaria com uma lógica condicional bagunçada. Com ele, cada método de pagamento se torna sua própria estratégia:
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}A classe context mantém uma referência a uma estratégia e delega o trabalho a ela. A chave é que o contexto não sabe qual estratégia concreta está usando — ele conhece apenas a interface:
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Agora você pode alterar o comportamento de pagamento dinamicamente:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Pago 100 via Cartão de Crédito
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Pago 50 via PayPalO Padrão Strategy brilha quando você tem várias maneiras de realizar uma ação e deseja alternar entre elas facilmente. Adicionar um novo método de pagamento significa simplesmente criar uma nova classe que implementa PaymentStrategy—nenhuma alteração no código existente é necessária.
Desafio
FácilVamos construir um sistema de formatação de texto usando o Strategy Pattern! Você criará um sistema onde diferentes estratégias de formatação podem ser trocadas em tempo de execução para transformar o texto de várias maneiras — perfeito para uma aplicação que precisa suportar múltiplos formatos de saída.
Você organizará seu código em quatro arquivos:
TextFormatter.java: Defina a interfaceTextFormatterque todas as estratégias de formatação implementarão. Ela deve declarar um único métodoString format(String text)que recebe uma string e retorna a versão formatada.Formatters.java: Crie três estratégias concretas que implementam sua interfaceTextFormatter:UpperCaseFormatter- transforma o texto em todas as letras maiúsculas.LowerCaseFormatter- transforma o texto em todas as letras minúsculas.TitleCaseFormatter- coloca a primeira letra de cada palavra em maiúscula, mantendo o restante em minúscula. As palavras são separadas por espaços.TextEditor.java: Crie a classe de contexto que utiliza uma estratégia de formatação. SeuTextEditordeve ter:Um campo privado para armazenar a estratégia
TextFormatteratual.Um método
setFormatter(TextFormatter formatter)que altera a estratégia de formatação ativa.Um método
publishText(String text)que aplica o formatador atual ao texto e imprimePublished: [formatted text]. Se nenhum formatador tiver sido definido, ele deve imprimirPublished: [original text]sem alterações.Main.java: Reúna seu sistema de estratégia! Você receberá duas entradas: o texto a ser formatado (String) e o estilo de formatação (String:"upper","lower", ou"title").Crie um
TextEditore primeiro chamepublishTextcom seu texto de entrada antes de definir qualquer formatador (demonstrando o comportamento padrão).Em seguida, com base na entrada de estilo, defina a estratégia de formatador apropriada e chame
publishTextnovamente com o mesmo texto para mostrar o resultado formatado.
Você receberá duas entradas em ordem: o texto a ser formatado (String) e o estilo de formatação (String).
Por exemplo, com as entradas hello world e title, sua saída seria:
Published: hello world
Published: Hello WorldObserve como o TextEditor não sabe nada sobre a lógica de formatação específica — ele simplesmente delega para qualquer estratégia que esteja definida no momento. Isso torna trivial a adição de novos estilos de formatação sem tocar no código do editor!
Folha de consulta
O Strategy Pattern (Padrão de Estratégia) é um padrão de design comportamental que define uma família de algoritmos, encapsula cada um em sua própria classe e os torna intercambiáveis. Ele permite trocar algoritmos em tempo de execução sem alterar o código que os utiliza.
Componentes Chave
Strategy Interface: Define a interface comum para todas as estratégias concretas.
interface PaymentStrategy {
void pay(int amount);
}Concrete Strategies: Implementam a interface de estratégia com algoritmos específicos.
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}Context Class: Mantém uma referência para uma estratégia e delega o trabalho a ela. O contexto conhece apenas a interface, não a implementação concreta.
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}Uso
As estratégias podem ser alteradas dinamicamente em tempo de execução:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Paid 100 via Credit Card
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Paid 50 via PayPalBenefícios
O Strategy Pattern é ideal quando você tem várias maneiras de realizar uma ação e deseja alternar entre elas facilmente. Adicionar uma nova estratégia significa simplesmente criar uma nova classe que implementa a interface de estratégia — nenhuma alteração no código existente é necessária.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String style = scanner.nextLine();
// TODO: Criar uma instância de TextEditor
// TODO: Chamar publishText com o texto de entrada (antes de definir qualquer formatador)
// TODO: Com base na entrada de estilo ("upper", "lower" ou "title"),
// definir o formatador apropriado e chamar publishText novamente
}
}Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator