E ai galera,
já faz um bom tempinho que não posto nada aqui, ultimamente estou meio ocupado.
Li uns artigos que diziam que quando se tem muitos “if’s” em um código, ele perde a característica de orientação a objeto.
Achei um exercicio na net que fiquei na duvida de como implementar ele orientado a objeto.:
Classe Taxa de
Ano do modelo Peso de peso registro
1970 ou antes Menos de 1200 kg 1 16,50
de 1200 a 1700 kg 2 25,50
Mais de 1700 kg 3 46,50
1971 a 1979 Menos de 1200 kg 4 27,00
de 1200 a 1700 kg 5 30,50
Mais de 1700 kg 6 52,50
1980 ou depois Menos de 1600 kb 7 19,50
3600 kg ou mais 8 52,50
Neste exercicio eu devo implementar um programa para calcular a taxa de registro de acordo com o ano e o peso do automovel.
Ja fiz esse exercicio, porem com muitos if’s neles.
Tentei achar uma maneira de tirar esses if’s, mas não consegui.
Será que alguem sabe como eliminar essa estrutura e deixar o codigo mais orienteado a objeto?
Vc tem várias formas de resolver. OO é como fazer bolos, o mesmo bolo pode ser feito de formas diferentes por diferentes cozinheiros (claro que o sabor será diferente … 8) )
Vc identificou classes de peso por um numero. Vc poderia usar esse numero para obter a taxa. É bem linear
Mas tlv vc queria fazer algo mais generico. Dado o ano do carro e o peso calcular a taxa.
Bom, vc vai precisar de um calculador de taxas que muda sua logica conforme o ano e a taxa
O uso seria mais ou menos assim:
CalculadorTaxa cal = CalculadorTaxa.getInstance(1990); //1990 é o ano
double taxa = cal.getTaxa(1230); // 1230 é o peso
Não se trata de criar um singleton e sim um abstract factory. A classe CalculadorTaxa tem logica dinamica , ou seja, a logica muda no tempo ( conforme mudam as leis ,etc…)
class abstract CalculadorTaxa {
public static CalculadorTaxa getInstance(int ano, double peso){
if (ano<=1970){
return CalculadorTaxa1970();
} else if (ano < 1980){
return CalculadorTaxa1971();
} else {
return CalculadorTaxa1980();
}
}
public abstract double getTaxa(double peso);
protected class CalculadorTaxa1971{
public double getTaxa(double peso){
if (peso < 1200){
return 27;
} else if (peso < 1700){
return 30.50;
} else {
return 52.50
}
}
}
// .. o mesmo para as outras classes
}
Bom, vendo bem os ifs não desapareceram…
Suponho que poderiamos usar um mecanismo de matrizes, mas esse não é o ponto.
Alguem consegue fazer com menos ifs ?
Você pode fazer a classe CalculadorTaxa saber em que anos ela trabalha. Depois, basta cadastrar objetos dessa classe numa lista e perguntar para eles, ao invés de fazer com ifs.
public CalculadorTaxa getCalculadorParaOAno(int ano) {
for (CalculadorTaxa calculador : calculares) {
if (calculador.workForYear(ano))
return calculador;
return null; //Nenhum calculador para aquele ano
}
Os ifs do peso são mais difíceis de eliminar, pois são muito específicos do calculador de taxas. Eu imagino que poderia usar a mesma estratégia, mas acho que os benefícios não seriam tão grandes assim.
Fazer um enum de calculadores de taxa, como mostrei no artigo ali em cima, também pode ser uma boa. Aí aquele método ali em cima poderai ser estático, obtendo o objeto do enum adequado de acordo com o ano.
[quote=ViniGodoy]Você pode fazer a classe CalculadorTaxa saber em que anos ela trabalha. Depois, basta cadastrar objetos dessa classe numa lista e perguntar para eles, ao invés de fazer com ifs.
public CalculadorTaxa getCalculadorParaOAno(int ano) {
for (CalculadorTaxa calculador : calculares) {
if (calculador.workForYear(ano))
return calculador;
return null; //Nenhum calculador para aquele ano
}
[/quote]
É uma boa, eu tinha pensando em usar map, mas não estava vendo que chave usar.
E como estipular para os calculadores finais? Por exemplo, o calculador de 71 a 79 era válido em 77
e o codigo de workForYear() deveria seria : return ano > 1970;
Mas em 80 aparece outro e o codigo tem que ser mudado para return ano > 1970 && ano < 1980
Isso provoca a edição de um calculador em vez da edição da fábrica. Será que isto compensa a retirada dos ifs ?
[quote]
Fazer um enum de calculadores de taxa, como mostrei no artigo ali em cima, também pode ser uma boa. Aí aquele método ali em cima poderai ser estático, obtendo o objeto do enum adequado de acordo com o ano.[/quote]
Mas isso é a mesma coisa. Vc teria que usar um getCalculadorParaOAno(ano) do mesmo jeito para descobrir qual enum seria o bom. O Enum só seria melhor se fosse ser usado explicitamente todas as vezes, o que provavelmente não é o caso já que a informação está num outro objeto (Carro, p.ex.).
Acho que compensa. Quando você editar um novo calculador, supondo que todos os calculadores tenham uma interface em comum, vai ter que se preocupar com o método workForYear. Fica bastante explícito. Se você manter um if, vai ter que se lembrar que esse if está em algum lugar (e torcer para que esteja em só um lugar). Me parece lógico que essa regra de negócio, já que está diretamente relacionada a funcionalidade de um calculador, esteja implementada no próprio calculador em si.
Você também pode obter calculadores dinamicamente, seja por algum mecanismo de injeção de dependência, por um cadastro externo ou por um registro qualquer.
E, por fim, esse método também pode acabar se tornando útil em outros trechos do código.
É realmente a mesma coisa. O enum é interessante pq a lista de values() já é implementada em built-in. Mas, como você mesmo falou, só é legal quando o conjunto de valores é relativamente fixo e pode ser usado diretamente, como no caso do enum que dei no exemplo (onde um SearchCriteria vai ser usado diretamente em vários trechos do código).
To tao ocupado que so tive tempo de implementar agora.
Implementei usando polimorifsmo Nao consegui eliminar os ifs, mas a ideia me ajudou a deixar o codigo mais reutilizavel.
Com os enums nao consegui implementar nessa situação. Mas fiz em uma outra situação onde os valores eram fixos, e ficou bem legal a solução.