Strategy — Padrões de Projeto em Java
Nosso sistema já esta rodando em produção, porém precisamos adicionar uma nova funcionalidade: Cálculo de Impostos, a princípio você deve estar pensando:
Isso é simples, vou criar uma classe, passar o imposto e o valor à ser calculado e calcular.
Não é bem assim que funciona, para o exemplo do post vou utilizar a linguagem Java.
Pedimos para o nosso desenvolvedor João implementar a nova funcionalidade, um tempo depois ele nos enviou:
Como podemos ver, o cálculo esta funcionando, porém observando um pouco mais o código, podemos fazer algumas observações:
- Ele esta passando como
String
o nome do imposto seguido pelo seu valor. - Estamos programando em uma linguagem OO(Orientada a Objetos), porém, o código esta procedural.
- Se amanhã surgir um novo imposto, vamos ter novos
if's
.
Simples observações que fazem toda a diferença, imagine que agora, pedimos para o João adicinar um novo imposto, então ele adicionou e nos enviou o código para revisão:
Veja que precisamos adicionar um novo if
, caso você já tenha estudado um pouco sobre padrões de projetos ou boas prátias em linguagens OO, já deve estar doido com esse código kkk. Calma, vamos devagar para tudo dar certo, nossa classe tem a tendência de crescer para sempre, chamamos essa classe de Não coesa, então como podemos resolver isso? Utilizar algum padrão de projeto.
Strategy
Para exemplo do post vamos utilizar o padrão Strategy, com ele conseguimos realizar a mesma operação de diferentes maneiras, caso queira se aprofundar um pouco mais em Design Patterns(Padrões de Projeto) recomendo o livro Design Patterns em Java da Casa do Código ou esse artigo Entendendo os conceitos dos Padrões de Projetos em Java da DevMedia.
O que é um Padrão de Projeto?
Com certeza vários sistemas já tiveram que realizar seus cálculos de impostos, podemos generalizar de maneira diferente, ou seja, já tiveram que realizar a mesma função de diferentes maneiras. Agora imagine que cada desenvolver ou empresa resolva e implemente tal necessidade do seu jeito, a probabilidade de todos os códigos serem diferentes é quase certa, cada pessoa tem sua lógica e raciocínio, portanto, não teríamos reaproveitamento de código.
Baseado nessa ideia surgiu os Padrões de Projetos, uma solução comúm desenhada para determinadas situações, por exemplo, para realizar a mesma função de diferentes maneiras temos o Strategy, para criação de objetos complexos temos a Factory e muitos outros nomes para respectivas necessidades, cabe a você analisar a situação e tentar aplicar um padrão para resolver, esse assunto foge do contexto do post.
Refatorando nosso código
Existem diversas definições para Refatoração de Código aqui de forma geral para não entrar no contexto, irei definir Refatoração como reescrita e melhora em nosso código, assim, vamos transformar aquele código até então em procedural para orientado a objetos.
Voltando ao exemplo:
O que podemos ver de igualdade nesse código? A resposta é simples: Imposto, todos os if's
são baseados em impostos, então vamos começar transformando os if's
em classes:
Mas até o momento ICMS
e IPI
não passam de classes comúns para nós, precisamos definir de alguma maneira que elas são Impostos, como podemos fazer isso?
Programe voltado para Interfaces
Se você já estudou ou pesquisou um pouco sobre Java, com certeza já deve ter ouvido falar nessa frase: “Programe voltado para Interfaces”, mas afinal, o que seria essa tal de interface? Interfaces são espécies de “contratos” que nossas classes podem assinar, após assinar o contrato você deve respeitar tudo que contém nele, vamos trazer o exemplo para o mundo real.
Imagine que José quer ser um jogador de futebol, então o empresário dele o leva para fazer um teste no seu primeiro time, após concluir o teste o time gostou de José e querem assinar um contrato com ele, até esse momento José ainda é um menino normal, porém após assinar o contrato ele será um Jogador de futebol e deverá respeitar tudo o que esta escrito no contrato, seja com objetivos ou metas do time, função, etc…
Voltando ao nosso mundo Java, como podemos criar um contrato?
Pronto, nosso contrato já estra criado, transformamos o contrato do mundo real em Interface
no mundo Java, porém não contém nenhuma regra, o que podemos definir em nosso contrato? Se olharmos nosso código cheio de if
podemos ver que trata-se da realização do cálculo de um imposto, então quem assinar o contrato Imposto
deve saber se calcular, vamos adicionar a primeira regra:
Primeira e única regra adicionada, agora temos certeza que todas as classes que assinarem esse contrate deverão saber como se calcular.
Assinando o contrato
Já temos nosso contrato pronto e já explicamos como funciona uma Interface
, agora, como podemos fazer nossas classes assinarem o mesmo?
Como podem ver, através da palavra implements
dizemos ao Java: "Agora a classe ICMS implementa(assina) a interface(contrato) Imposto", com isso, ela passa a não ser uma classe comúm mas também é do tipo Imposto
. Após assinar esse contrato com Imposto
nossa classe não deve estar compilando, por que isso esta acontecendo?
Cumprindo as regras do contrato
Lembra que definimos apenas uma regra em nosso contrato? Pois é, agora precisamos fazer com que a classe ICMS
cumpra e respeite essa regra. De forma geral, todas as regras existentes em nosso contrato que não estiverem escritas, devem ser escritas por quem o assinou, mas como podemos escrever essas regras?
Veja que através da palavra override
estamos "sobrescrevendo" a regra calcular
, essa sobrescrita deve ser feita para todas as regras não escritas e declaradas em nossa Interface
. Até ai tudo bem, mas vamos sempre devolver zero no cálculo? Precisamos passar o valor para o imposto realizar o calculo, se precisamos "passar" valor para a classe, nada melhor do que o construtor para realizar essa função:
Pronto, já temos o valor, já assinamos o contrato, falta apenas escrever o método calcular
de maneira correta:
Pronto, nossa classe ICMS
esta pronta, estamos calculando os mesmos 10% de antes, agora vamos implementar a classe IPI
:
Veja que a classe IPI
ainda continua calculando os 20%.
Polimorfismo
Calma, não fique assustado, para todo nome tem uma explicação. Podemos dizer que Polimorfismo é uma forma de você utilizar interfaces em nosso códigos que em tempo de execução serão substituídas por nossas classes que implementam essas interfaces, calma, não fique assustado, com o exemplo vocês irão entender, lembra da nossa CalculadoraDeImpostos
:
Eu sei, é impossível esquecer esse código kkkk, agora, podemos apenas passar para o método calcular
os nossos Impostos, mas como podemos fazer isso? Vamos ter que passar todas as classes?
Eu sei, é bem chocante a diferença, olha que coisa mais linda, um código limpo, coeso, simples e eficiênte, esse é o uso de Polimorfismo, estamos passando nossa interface(contrato) como parâmetro do método, agora, qualquer classe que implementa de Imposto
pode ser passada para o método, ainda não acredita? Veja o código de teste como ficou:
Eu sei, ainda deve estar em dúvida, então abaixo o código sendo testado:
Agora sim, um código com padrão e orientado a objetos, se amanhã ou depois surgir um novo imposto, preciamos apenas criar mais uma classe e tudo ainda continuará funcionando.
E ai, gostou? Não deixe de comentar.
Publicado em blog.matheuscastiglioni.com.br.