
O que é o Padrão Strategy?
O padrão Strategy é um padrão de design comportamental que permite definir uma família de algoritmos, encapsulá-los e torná-los intercambiáveis. Esse padrão permite que o algoritmo varie independentemente dos clientes que o utilizam. Em outras palavras, ele permite que você escolha o algoritmo a ser usado em tempo de execução.
Benefícios do Padrão Strategy
- Manutenção Facilitada: Com o Strategy, você pode adicionar novas estratégias (algoritmos) sem modificar o código existente, seguindo o princípio aberto/fechado (Open/Closed Principle).
- Redução da Duplicação de Código: Encapsulando algoritmos em classes separadas, evitamos duplicação de código e promovemos o reuso.
- Melhoria na Testabilidade: Testar cada estratégia isoladamente é mais fácil do que testar uma classe com múltiplos comportamentos embutidos.
- Flexibilidade: Permite que os algoritmos sejam escolhidos e alterados em tempo de execução, oferecendo maior flexibilidade na aplicação.
Quando usar o Padrão Strategy?
- Quando você tem muitas classes relacionadas que diferem apenas no comportamento.
- Quando você precisa de diferentes variações de um algoritmo.
- Quando os algoritmos específicos das classes podem ser expostos para que outros objetos possam interagir com eles.
- Substituição de if e switch-case.
Exemplo de Implementação em Java
Enum para auxiliar na escolha de estratégia:
package com.example.demo.strategy;
public enum DiscountType {
CHRISTMAS,
NEW_YEAR,
EASTER
}
Interface das estratégias:
package com.example.demo.strategy;
import java.math.BigDecimal;
public interface DiscountStrategy {
BigDecimal applyDiscount(BigDecimal price);
boolean selector(DiscountType discountType);
}
Estratégias
package com.example.demo.strategy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class ChristmasDiscountStrategy implements DiscountStrategy{
@Override
public BigDecimal applyDiscount(BigDecimal price) {
return price.multiply(BigDecimal.valueOf(0.90)); // 10% de desconto
}
@Override
public boolean selector(DiscountType discountType) {
return DiscountType.CHRISTMAS.equals(discountType);
}
}
package com.example.demo.strategy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class EasterDiscountStrategy implements DiscountStrategy{
@Override
public BigDecimal applyDiscount(BigDecimal price) {
return price.multiply(BigDecimal.valueOf(0.80)); // 20% de desconto
}
@Override
public boolean selector(DiscountType discountType) {
return DiscountType.EASTER.equals(discountType);
}
}
package com.example.demo.strategy;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Component
public class NewYearDiscountStrategy implements DiscountStrategy{
@Override
public BigDecimal applyDiscount(BigDecimal price) {
return price.multiply(BigDecimal.valueOf(0.85)); // 15% de desconto
}
@Override
public boolean selector(DiscountType discountType) {
return DiscountType.NEW_YEAR.equals(discountType);
}
}
Como implementar a seleção da estratégia
É muito comum ver essa seleção de estratégia sendo implementada com a inserção manual dessas mesmas estratégias na lista. Mas podemos utilizar o próprio spring pra isso, tendo declarado todas estratégias como componentes do spring. Como fizemos acima. Então quando criamos uma lista de estratégias, e pedimos o lombok pra criar um construtor com argumentos necessários, as estratégias já são inseridas automaticamente, sem a necessidade de inserção manual.
package com.example.demo.service;
import com.example.demo.strategy.DiscountStrategy;
import com.example.demo.strategy.DiscountType;
import jakarta.el.MethodNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class DiscountService {
private final List<DiscountStrategy> strategies;
public DiscountStrategy getStrategy(DiscountType discountType){
return strategies.stream().filter(strategy -> strategy.selector(discountType))
.findFirst()
.orElseThrow(MethodNotFoundException::new);
}
}
Conclusão
O padrão Strategy é uma poderosa ferramenta para separar os algoritmos das classes que os utilizam, permitindo flexibilidade e facilidade de manutenção. É especialmente útil em situações onde você precisa de múltiplas variações de um algoritmo e deseja selecionar qual usar em tempo de execução.
Código completo: https://github.com/nathalia-amarals/strategy-java-spring-boot

