O padrão Strategy é um padrão de design comportamental que tem como objetivo principal permitir a definição de uma família de algoritmos, encapsular cada um deles como um objeto e torná-los intercambiáveis.
Este padrão permite que o algoritmo varie independentemente dos clientes que o utilizam. O Strategy resolve vários problemas comuns em design de software:
-
Flexibilidade de Algoritmos: Em muitos sistemas, é necessário alternar entre diferentes algoritmos ou políticas em tempo de execução. O Strategy permite essa flexibilidade sem a necessidade de condicionais complexas e sem acoplamento ao código cliente.
-
Reutilização de Código: O padrão Strategy promove a reutilização de código ao separar comportamentos específicos em classes independentes que podem ser utilizadas por diferentes contextos.
-
Eliminação de Condicionais Complexas: Em vez de usar múltiplas condicionais para alternar entre diferentes comportamentos ou algoritmos, o padrão Strategy encapsula cada comportamento em sua própria classe, simplificando o código e melhorando a manutenção.
-
Encapsulamento de Variações de Comportamento: O Strategy encapsula variações de comportamentos que são semelhantes, mas têm detalhes específicos que os diferenciam, fornecendo uma estrutura clara para a representação de várias versões de um algoritmo.
Como Funciona
O padrão Strategy envolve três componentes principais:
- Contexto: Uma classe que contém uma referência a um objeto Strategy. Ele é configurado com um objeto Strategy concreto e pode definir uma interface que permite que os clientes especifiquem o Strategy desejado.
- Strategy (Interface ou Classe Abstrata): Define uma interface comum para todos os algoritmos suportados. Contexto usa esta interface para chamar o algoritmo definido pelo Strategy concreto.
- Strategies Concretos: São implementações da interface Strategy, cada uma encapsulando um algoritmo ou comportamento específico.
Exemplo
Um exemplo comum do uso do padrão Strategy é em sistemas de pagamento, onde diferentes estratégias podem ser usadas para processar pagamentos (como pagamento por cartão de crédito, PayPal, criptomoedas, etc.). Cada método de pagamento seria implementado como um Strategy concreto, e o sistema poderia alternar entre eles em tempo de execução conforme necessário.
Exemplo de Implementação
Vamos criar um exemplo simples do padrão Strategy em Java. Vamos desenvolver um sistema simples de ordenação, onde diferentes estratégias de ordenação podem ser aplicadas a uma lista de números. Vamos implementar duas estratégias de ordenação: uma para ordenação crescente e outra para decrescente.
Interface Strategy
Primeiro, definimos a interface EstrategiaOrdenacao que será implementada por todas as estratégias de ordenação:
import java.util.List;
public interface EstrategiaOrdenacao {
void ordenar(List<Integer> lista);
}Estratégias Concretas
Implementamos duas estratégias concretas para ordenação crescente e decrescente:
import java.util.Collections;
import java.util.List;
public class OrdenacaoCrescente implements EstrategiaOrdenacao {
@Override
public void ordenar(List<Integer> lista) {
Collections.sort(lista);
}
}
public class OrdenacaoDecrescente implements EstrategiaOrdenacao {
@Override
public void ordenar(List<Integer> lista) {
lista.sort(Collections.reverseOrder());
}
}Contexto
Agora, criamos a classe ContextoOrdenacao que usa um objeto EstrategiaOrdenacao para ordenar uma lista de números:
import java.util.List;
public class ContextoOrdenacao {
private EstrategiaOrdenacao estrategia;
public ContextoOrdenacao(EstrategiaOrdenacao estrategia) {
this.estrategia = estrategia;
}
public void ordenarLista(List<Integer> lista) {
estrategia.ordenar(lista);
}
public void setEstrategia(EstrategiaOrdenacao estrategia) {
this.estrategia = estrategia;
}
}Testando o Padrão Strategy
Por fim, utilizamos o padrão Strategy para ordenar a lista de números:
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> lista = Arrays.asList(3, 1, 4, 1, 5, 9);
ContextoOrdenacao contexto = new ContextoOrdenacao(new OrdenacaoCrescente());
contexto.ordenarLista(lista);
System.out.println("Ordenação Crescente: " + lista);
contexto.setEstrategia(new OrdenacaoDecrescente());
contexto.ordenarLista(lista);
System.out.println("Ordenação Decrescente: " + lista);
}
}Neste exemplo, a classe ContextoOrdenacao é configurada com uma estratégia específica (OrdenacaoCrescente ou OrdenacaoDecrescente) para ordenar a lista. Isso demonstra como o padrão Strategy permite alternar entre diferentes algoritmos (estratégias) em tempo de execução sem alterar o código cliente.