Padrão de Projeto Strategy: O que é, quando devo usar, como aplicar e exemplos!
Entre os diferentes padrões de projeto, o Strategy permite criar uma família de algoritmos, encapsular cada um deles e torná-los intercambiáveis, permitindo que o algoritmo varie independentemente dos clientes que o utilizam e facilitando a manutenibilidade do seu código.
Se você está iniciando no mundo de padrões de projeto e qualidade de código, mas ainda não sabe bem como usar o Strategy, não se preocupe.
Vamos te mostrar hoje o que é o Strategy, quando usar e como aplicar, com exemplos. Você vai perceber que este padrão é mais simples do que pensa e que ele pode te ajudar bastante no seu dia a dia. Confira!
O que é o Padrão Strategy?
O Strategy é um padrão de projeto comportamental que define uma família de algoritmos, garantindo que o algoritmo varie independentemente dos clientes que fazem uso dele.
Com ele, você pode transformar um conjunto de comportamentos em objetos e então torná-los intercambiáveis.
Hoje, iremos abordar somente o Strategy. Mas, além dele, existem outros padrões de projeto em Java, como por exemplo, o Composite e o Decorator, que são abordados no livro Padrões de Projeto da GoF, a Gang of Four - ou em português, Gangue dos Quatro, caso você tenha interesse em explorar mais o assunto.
Ainda de acordo com a Gangue dos Quatro, no livro Design Patterns: Elements of Reusable Object-Oriented Software, temos a seguinte definição:
“Um padrão de projeto nomeia, abstrai e identifica os aspectos-chave de uma estrutura de projeto comum para torná-la útil para a criação de um projeto orientado a objetos reutilizável […]”.
Como funciona o Padrão de Projeto Strategy?
Vamos entender como funciona o Strategy Design Pattern: imagine que temos um e-commerce e no carrinho de compras da loja podemos aplicar algumas promoções dependendo de vários fatores.
Por exemplo, é possível aplicar uma promoção de acordo com o valor mínimo de compra, a quantidade de produto, frete grátis, entre outros.
Neste cenário, podemos ter muitas variações de algoritmos dentro do carrinho de compras. Porém, ao fazer tudo isso dentro da classe de carrinho sem separar o algoritmo, provavelmente haveria várias condicionais IFS para checar em quais casos aplicar cada promoção, gerando diversas alterações da classe do carrinho.
É aí que o Strategy entra, pois ele soluciona esse problema separando o algoritmo.
Dessa forma, dentro do carrinho de compras, teremos um campo para linkar uma estratégia de desconto que será uma família inteira de estratégias.
Ou seja, podemos separar o algoritmo da regra de negócio.
Quando devo usar o padrão Strategy?
O padrão Strategy é muito comum no código Java e pode ser usado em situações em que o seu código terá muitas variações de algoritmo e condições, gerando uma corrente de IFs.
Vale reforçar que não são todas as cadeias de IFs que precisam ser substituídas por um Strategy, apenas se as alterações forem frequentes a longo prazo.
Este padrão ajuda a facilitar a manutenibilidade do código e tornar a potencial expansão do seu código mais simples e objetiva.
Isso é possível através da descentralização da responsabilidade da manipulação de um objeto abstraído por uma interface e suas diferentes “estratégias” de implementação.
Como aplicar o Strategy na prática?
Agora que você já entendeu melhor o conceito do padrão Strategy e quando utilizá-lo, vamos sair um pouco da parte teórica e partir para a prática.
Vamos visualizar um problema e refletir sobre ele para, então, testar a implementação do design pattern em questão.
Exemplo de aplicação Strategy Java: O Problema
Para entender melhor como aplicar o Strategy, imagine que existe um objeto Funcionario com suas propriedades e uma classe CalculadoraSalarial que realiza o reajuste salarial deste funcionário de acordo com sua performance durante o ano.
Com um ENUM que existe dentro das propriedades do objeto Funcionario, mede-se a performance do colaborador. Veja no exemplo a seguir:
Agora, imagine as seguintes regras de negócio:
- Se o funcionário tiver uma performance NEGATIVA no momento do cálculo, ele não deve receber reajuste salarial.
- Se o funcionário tiver uma performance POSITIVA no momento do cálculo, seu salário deve receber um reajuste com aumento salarial de 5%.
Devido a lógica por trás do negócio, o ideal é não retornar um valor de reajuste “X” por padrão.
Dessa forma, podemos criar uma exceção caso no futuro exista algum novo tipo de performance que esquecemos de implementar na nossa calculadora.
Implementando o método reajustaSalario (no exemplo, utilizando Java), podemos chegar a um resultado parecido com o seguinte:
O código acima está funcional. Porém, uma semana após a implementação, vamos supor que o time solicitou a criação de um novo tipo de performance: EXCELENTE.
Nesta nova condição, o colaborador que conquistar a performance “excelente” recebe 10% de reajuste salarial.
Sendo simples e direto, o ENUM seria implementado com mais um tipo, o “EXCELENTE”. Por último, a implementação do método reajustaSalario ficaria semelhante ao exemplo abaixo:
É em cenários parecidos com este que o padrão Strategy é aplicado: onde o código pode facilmente se expandir criando uma corrente de IFs.
No exemplo acima, estamos “pegando leve” ─ no mundo real, encontra-se IFs encadeados em uma frequência muito mais comum, muitas vezes em situações piores do que o nosso.
Tudo isso prejudica a legibilidade do código e não é uma boa prática.
E como podemos implementar o Strategy nesse caso?
Existem diversas formas de se resolver um problema com Strategy, a maioria delas envolve a implementação de uma interface ou de uma abstração.
No nosso exemplo, as coisas são bem mais simples graças ao nosso ENUM.
Provavelmente, até agora, a nossa implementação de Performance foi a seguinte:
A partir de então, ao implementarmos um método abstrato dentro do nosso ENUM, todos os diferentes tipos dentro dele exigirão uma implementação, causando erro em tempo de compilação caso essa exigência não seja atendida, obrigando o desenvolvedor a implementar o método.
E, assim, podemos alterar a forma que a nossa calculadora retorna o reajuste salarial do funcionário.
Isso facilita imensamente a leitura do código e sua manutenção, tornando ele mais simples.
Este processo deverá seguir os princípios SOLID (cinco princípios da Programação Orientada a Objetos). Aproveite para ler nosso artigo sobre um dos princípios mais importantes do SOLID: Single Responsability Principle.
Depois de aplicar o Strategy, basicamente, contanto que a regra de negócio fundamental não mude, não precisamos mais sequer tocar na nossa “Calculadora”.
Como temos certeza de que o método retornaReajusteSalarial possui sua devida implementação dependendo do tipo de performance, garantimos, também, que não exista o cenário descrito anteriormente, onde o desenvolvedor esqueceu de implementar o cálculo do reajuste.
É importante reforçar que esta não é a única forma de implementar o padrão de projeto Strategy, mas é um ótimo jeito de exemplificar como é mais fácil de implementá-lo no nosso código do que você imagina.
Opinião do Autor sobre o Padrão de Projetos Strategy
Por mais que seja diversas vezes confundido por parecer complexo, o Strategy é bem mais simples de ser implementado do que parece e poderia muito bem ser mais visto no código de vários sistemas orientados a objeto.
Durante o desenvolvimento, às vezes podemos acabar criando a ideia errada de que tentar aplicar Design Patterns consome muito tempo.
Na verdade, uma vez que você conhece e domina Design Patterns, eles só têm a agregar para a velocidade e elegância da sua solução.
Os padrões de projeto facilitam o desenvolvimento e tornam a manutenibilidade e evolução do código mais simples.
E você, já aplicou o Strategy em algum dos seus códigos? O que achou do deste design pattern? Deixe seu comentário!