IF BOM É IF MORTORefatoração de código com o pattern Strategy
Jackson Veroneze - [email protected] Mendonça - [email protected]
Cenário Imagine que o Governo possua um sistema que calcula o valor dos impostos de receitas vindas de diversas fontes.
Codificação
public class CalculadorDeImpostos {
public double calculaImposto(double receita, String tipoDeImposto) {
double imposto = 0;
if (tipoDeImposto.equals("IPI"))
imposto = receita * 0.15;
else if (tipoDeImposto.equals("ISS"))
imposto = receita * 0.06;
else if (tipoDeImposto.equals("ICMS"))
imposto = receita * 0.08;
return imposto;
}
}
Problema Enorme quantidade de IFs que a classe possui.
Tende a crescer à medida que novos impostos vão sendo criados, gerando mais complexidade ao código.
Problema
public class CalculadorDeImpostos {
public double calculaImposto(double receita, String tipoDeImposto) {
double imposto = 0;
if (tipoDeImposto.equals("IPI"))
imposto = receita * 0.15;
else if (tipoDeImposto.equals("ISS"))
imposto = receita * 0.06;
else if (tipoDeImposto.equals("ICMS"))
imposto = receita * 0.08;
else if (tipoDeImposto.equals("IR"))
imposto = receita * 0.03;
else if (tipoDeImposto.equals("IOF"))
imposto = receita * 0.02;
else if (tipoDeImposto.equals("IPVA"))
imposto = receita * 0.05;
else if (tipoDeImposto.equals("CPMF"))
imposto = receita * 0.03;
else if (tipoDeImposto.equals("IPTU"))
imposto = receita * 0.07;
else if (tipoDeImposto.equals("ITR"))
imposto = receita * 0.07;
return imposto;
}
}
IF BOM É IF MORTO
Questionamento - "Mas se não posso usar nem IF, nem Switch-Case, nem nada parecido, COMO é que vou tratar isso?"
Strategy, a salvação
SOLUÇÃO
SOLUÇÃO O padrão Strategy permite que você crie novos objetos (ex: "IPTU", "IPVA", etc) de um mesmo grupo (ex: "Impostos"), sem alterar a classe com a qual opera (ex: "Calculador de Impostos").
1º passo public interface Imposto { double calculaImposto(double receita); }
2º passopublic class IPI implements Imposto { public double calculaImposto(double receita) { return receita * 0.15; } }
public class ISS implements Imposto { public double calculaImposto(double receita) { return receita * 0.06; } }
public class ICMS implements Imposto { public double calculaImposto(double receita) { return receita * 0.08; } }
3º passo public class CalculadorDeImpostos { public double calculaImposto(double receita, Imposto imposto) { return imposto.calculaImposto(receita); } }
Teste do padrão
package br.eti.arquiteturacomputacional;
public class RealizaBalancoFinanceiro {
public static void main(String[] args) {
CalculadorDeImpostos calculador = new CalculadorDeImpostos();
//Calcula o imposto ICMS
Imposto icms = new ICMS();
double impostoAReceber = calculador.calculaImposto(500, icms);
System.out.println("ICMS de 500 = " + impostoAReceber);
//Calcula o imposto ISS
Imposto iss = new ISS();
impostoAReceber = calculador.calculaImposto(500, iss);
System.out.println("ISS de 500 = " + impostoAReceber);
}
}
Conclusão Podemos criar novos impostos, sem alterar qualquer código existente. Esse padrão chama-se Strategy porque entregamos uma estratégia (um imposto especializado) para um contexto (CalculadorDeImpostos).
if ($iPanamnese->getDeTpresposta() == 'O') {$opcoes = explode(';', $iPanamnese->getDeOpcoes());for ($x = 0; $x < count($opcoes); $x++)
$vlr[$x] = $opcoes[($x)];
$resposta = isset($values['campo' . $iPanamnese->getId()]) ?vlr[$values['campo' . $iPanamnese->getId()]] : '';
$ranamneseI->setDeResposta($resposta);} elseif ($iPanamnese->getDeTpresposta() == 'M') {
$opcoes = explode(';', $iPanamnese->getDeOpcoes());for ($x = 0; $x < count($opcoes); $x++)
$vlr[$x] = $opcoes[($x)];
$resp = '0';if (isset($values['campo' . $iPanamnese->getId()])) {
$tmp = $values['campo' . $iPanamnese->getId()];if (is_array($tmp)) {
foreach ($tmp as $opcao)$resp .= $vlr[$opcao] . ';';
$resp = substr($resp, 0, strlen($resp) - 1);} else {
$resp = 'NDA';}
}
$ranamneseI->setDeResposta($resp);} elseif ($iPanamnese->getDeTpresposta() == 'R') {
$resp = '0';if (isset($values['campo' . $iPanamnese->getId()])) {
$opcoes = explode(';', $iPanamnese->getDeOpcoes());if (isset($values['campo' . $iPanamnese->getId()])) {
$resp = $opcoes[$values['campo' . $iPanamnese->getId()]];
}}
$ranamneseI->setDeResposta($resp);} elseif ($iPanamnese->getDeTpresposta() == 'V' || $iPanamnese->getDeTpresposta() == 'D' || $iPanamnese->getDeTpresposta() == 'N') {
if (isset($values['campo' . $iPanamnese->getId()])) {$ranamneseI->setDeResposta($values['campo' . $iPanamnese->getId()]);
}}
Referências http://www.arquiteturacomputacional.eti.br/2013/02/padrao-de-projeto-strategy.html
http://marconems.blogspot.com.br/2010/06/if-bom-e-if-morto.html