Melhor pratica ?

27 respostas Resolvido
V
Essa seria a melhor prática para esse conjunto de condições?

if (days<=5 ){}

else if(days >= 6 && days <= 10 ){}

else if(days >= 11 && days <= 15){}

else if(days >= 16 && days <= 20){}

else if(days >= 21 && days <= 25){}

else if(days >= 26 && days <= 30){}

else if(days >= 30){}

Obrigado

27 Respostas

C

Essa atividade é para a faculdade? Acho que a ideia é fazer você usar um loop.

V

Não é não. É pra um sistema q estou fazendo. Qual seria a idéia do loop ?

J
Solucao aceita

Não vejo nenhum problemas nessas condições para mim é uma pratica correta!

D

Sim e uma boa pratica.
Agora se você quer algo mais elegante pode user o operador ternário que daria no mesmo.

condicao ? valor_se_verdadeiro : valor_se_falso

days <= 5 ? true : false;

days >= 6 && days <= 10 ? true : false;


R

Na verdade o jeito mais elegante é testar do maior para o menor. Fica mais legível:

if(days >= 30){
}else if(days > 25){
}else if(days > 20){
}else if(days > 15){
}else if(days > 10){
}else if(days > 5){
}
R

Só é possível usar o operador ternário se ele precisar atribuir valor. Se ele precisar executar um bloco de comandos, o operador não serve. E na prática, o operador ternário obscurece ainda mais o código.

G

Ta… Primeiro de tudo … O if eh bem explícito, mas qual o objetivo desse algoritmo? VC implementou ele p resolver qual problema?

T

Em que problema ira ser aplicado esta solução ?

Se a pergunta for somente em questão de sintaxe esta correto …

V

O Objetivo é q dependendo de quantos dias tem uma transação é tomada uma decisão …
Exemplo:
Estou devendo um boleto já 15 dias então ela vai entrar no range de 11 até 15 dias. Isso é para q eu possa calcular os juros, neste caso o Juros não é diário e sim por range de dias.

Isso funciona, mas queria saber se é a melhor maneira de se fazer isso é desta forma.

Obrigado.

S

@ViniciusAnalista, sei que vc jah deu essa pergunta como respondida, mas preciso contribuir, pois discordo da resposta aceita.

Dá uma olhada nesse link por exemplo. Encadeamento de IF é considerado uma PÉSSIMA prática, pois seu código fica muito engessado. Lembre-se sempre de uma das principais regras da orientação a objetos: seu código deve ser aberto para expansão, mas fechado para modificação.

Qualquer mudança na sua regra de negócio te obrigará a alterar seu encadeamento de IFs. Dá uma pesquisada em alguns design patterns, como Strategy ou Chain of Responsibility.

R

e como você aplicaria estas idéias no código do colega ?

S

@rmendes08, cada regra de negócio é traduzida em uma classe que deve implementar uma interface de acordo com o pattern escolhido.

Para o caso específico que ele indicou, acredito que o melhor seja o Chain of Responsibility, onde cada classe realizará a validação requerida, executará em caso de sucesso e passará para a próxima classe em caso de falha.

Dá uma conferida no link que coloquei que é bem simples de entender (eu acho rs). A única observação que vejo em relação a esse link, é que ele monta o encadeamento direto no construtor. Existe uma alternativa que é criar um método setProximo (por exemplo), e determinar com sets que é a próxima regra a ser validada na cadeia.

Você pode perguntar: mas isso não faz com que eu tenha que acrescentar código da mesma forma?
A questão não é acrescentar ou não código. Se uma regra nova foi inserida no sistema, é óbvio que código será acrescentado. Entretanto, o código ficará com legibilidade, manutenibilidade e flexibilidade superiores.

R

Cara, eu acho que aplicar um padrão de projeto neste caso é overengineering. Tá certo que o autor não colocou mais detalhes, mas se o caso é apenas calcular o valor dos juros não tem necessidade (é até incorreto) usar padrões de projeto. Supondo que o caso seja o seguinte:

double valorJuro = 0.0;

if(days >= 30){
  valorJuro = 20;
}else if(days > 25){
  valorJuro = 15;
}else if(days > 20){
  valorJuro = 12;
}else if(days > 15){
  valorJuro = 10;
}else if(days > 10){
  valorJuro = 8;
}else if(days > 5){
  valorJuro = 3;
}

perceba que o encadeamento de if’s compõe uma única regra, um único comportamento. Aplicar o CoR nesse cálculo criaria baixa coesão: uma única funcionalidade estaria espalhada por várias classes e estas classes estariam acopladas. Enfim, aplicar um padrão como Strategy ou o CoR só faz sentido se você estiver separando comportamentos. Eliminar if’s não é motivo para se criar classes ou aplicar padrões de projeto. São apenas sintomas, smells de que alguma coisa pode estar errada, mas não estará necessariamente.

S

Desenvolvimento é algo que cada um prefere de um jeito. Esse exemplo que ele passou é muito similar a uma simples aplicação de imposto. ICS, ICSM, são impostos que devem ser aplicados a situações diferentes, simplesmente multiplicando fatores diferentes. É a única coisa que eles fazem.

EU prefiro utilizar um dos patterns pra isso, e a lógica é bem similar ao caso acima.

Mas entendi seu ponto de vista e me parece que é mera questão de preferência, exceto a questão da coesão. Isso se chama desenvolvimento baseado em interface. E é bem antigo.

I

Da pra implementar melhor, mas também, como disseram, vai da preferência. Se tiver usando Java 8 (por causa dos lambdas), da pra fazer algo assim

`public class Ranges {

private static final Set<Integer> RANGE1 = Sets.newHashSet(1, 2, 3, 4, 5);
private static final Set<Integer> RANGE2 = Sets.newHashSet(6, 7, 8, 9, 10);
private static final Set<Integer> RANGE3 = Sets.newHashSet(11, 12, 13, 14, 15);
private static final Set<Integer> RANGE4 = Sets.newHashSet(16, 17, 18, 19, 20);
private static final Set<Integer> RANGE5 = Sets.newHashSet(21, 22, 23, 24, 25);
private static final Set<Integer> RANGE6 = Sets.newHashSet(26, 27, 28, 29, 30);

private static final Set<Set<Integer>> RANGES = Sets.newHashSet(RANGE1, RANGE2, RANGE3, RANGE4, RANGE5, RANGE6);

public void doSomething() {
	Map<Set<Integer>, Integer> map = ImmutableMap.of(
				RANGE1, 3,
				RANGE2, 5,
				RANGE3, 8,
				RANGE4, 10,
				RANGE5, 15
			);
	System.out.println(map.get(contains(12))); // returns 8
	System.out.println(map.get(contains(1))); // returns 3
	System.out.println(map.get(contains(23))); // returns 15
	System.out.println(map.get(contains(6))); // returns 5
}

private Set<Integer> contains(Integer day) {
	return RANGES.parallelStream().flatMap(r -> RANGES.stream())
			.filter(range -> range.contains(day)).findFirst().get();
}

public static void main(String[] args) {
	Ranges ranges = new Ranges();
	ranges.doSomething();
}

}`

No caso aí, usei o Guava pra Sets, ImmutableMap.
Caso não dê preferencia em fazer isso… eu pelo menos criaria os Sets com os ranges, já acho que ficaria mais limpo.

PS: Da pra melhorar mais ainda, no caso de passar o valor fixo, crio alguma interface e passo no meu map, ficando mais dinâmico o retorno. Ex:

`public class Ranges {

private static final Set<Integer> RANGE1 = Sets.newHashSet(1, 2, 3, 4, 5);
private static final Set<Integer> RANGE2 = Sets.newHashSet(6, 7, 8, 9, 10);
private static final Set<Integer> RANGE3 = Sets.newHashSet(11, 12, 13, 14, 15);
private static final Set<Integer> RANGE4 = Sets.newHashSet(16, 17, 18, 19, 20);
private static final Set<Integer> RANGE5 = Sets.newHashSet(21, 22, 23, 24, 25);
private static final Set<Integer> RANGE6 = Sets.newHashSet(26, 27, 28, 29, 30);

private static final Set<Set<Integer>> RANGES = Sets.newHashSet(RANGE1, RANGE2, RANGE3, RANGE4, RANGE5, RANGE6);

public void doSomething() {
	Map<Set<Integer>, Calcular> map = ImmutableMap.of(
				RANGE1, () -> 3,
				RANGE2, () -> 5,
				RANGE3, () -> 8,
				RANGE4, () -> 10,
				RANGE5, () -> 15
			);
	System.out.println(map.get(contains(12))); // returns 8
	System.out.println(map.get(contains(1))); // returns 3
	System.out.println(map.get(contains(23))); // returns 15
	System.out.println(map.get(contains(6))); // returns 5
}

private Set<Integer> contains(Integer day) {
	return RANGES.parallelStream().flatMap(r -> RANGES.stream())
			.filter(range -> range.contains(day)).findFirst().get();
}

public static void main(String[] args) {
	Ranges ranges = new Ranges();
	ranges.doSomething();
}

interface Calcular {
	Integer call();
}

}`

J

:joy: :joy: :joy: :joy: :joy: se o rapaz está começando java agr, deve ta ficando louco kkk ele deve pensar como um simples if’s se tornaram algo tão complexo, e não faço a mínima ideia do que os caras estão falando. por favor não entendam mal, não estou falando mal das suas respostas! :slight_smile:

R

Não é questão de preferência nem gosto pessoal. É critério mesmo.

O ponto que eu quero chegar é que o simples uso de if’s não é motivo para refatorar o código em um Pattern. O que tem que ser observado é se os if’s definem comportamentos diferentes. Um caso onde o Strategy seria aplicável seria o seguinte:

double calcularJuro(Documento doc){
   if(tipo == FINANCIAMENTO){
       //calcular juro simples
   }else if(tipo ==  xxx ){
       //calcular juro composto
   }else if(tipo == yyy){
       //calcular por sistema Price
   }

   return juro;
}

Nesse caso, faria todo o sentido separar o cálculo em classes especializadas, cada uma para um tipo cálculo de juro. Mas (acho que) não é o caso do do autor do tópico, volto a enfatizar os if’s não servem para selecionar tipos de comportamento, mas servem para calcular valores. Na prática é uma consulta a uma tabela.

R

E você tem mais é que criticar mesmo. Nunca trabalhei em um equipe que só tive seniores, e se o código está difícil a tal ponto que quem está começando não entende, é porque está errado mesmo.

Citando o mestre Fowler:

Any fool can write code that a computer can understand. Good programmers write code that humans can understand

J

Adoro essa frase do Fowler :heart_eyes:, a procura de um bom desenvolvedor e smp, deixar um código de maneira simples e eficiente, em alguns casos realmente é complexo, mas smp buscando a maneira mais simples de entender, para outros programadores que pegarem seu programa na empresa, não passar muita dor de cabeça para entender, smp buscando a forma simples e eficiente e bem documentada, para quem não conhece eu recomendo o programa Doxygen, ele gerá um documento do seu código, bem legal :slight_smile:

C

@rmendes08 tenho que concordar com o @sidneydemoraes pelo simples fato de que esses if encadeados quebram o Open Closed Principle que prega que suas classes devem ser abertas para extensão e fechadas para modificações. Imagine que uma nova regra foi introduzida nesse sistema. Dessa forma, o programador é obrigado a alterar a regra atual para adicionar um novo if, compilar todo o pacote novamente e passar todos os testes unitários novamente também. Concordo que os ifs são mais simples porém, não foram pensados orientados a objetos.

S

@JeanJavaMan: Concordo com sua declaração, mas uma coisa é falar que ele pode fazer assim no começo. Outra é falar que é boa prática. E vocês vão me desculpar, mas me apontem UM artigo de um profissional de respeito no mercado que diga que encadeamento de IFs é uma boa prática.

Então, quando respondermos, dividamos direito nossas respostas. Agora, dizer qué só uma equipe inteira de seniores entenderia isso, desculpa. Talvez você não seja tão senior assim. Qualquer iniciante em Java usa uma IDE e a primeira coisa que ele aprende é F3 pra seguir as chamadas de código. Outra: debugar esse código (ou pior, outros mais complexos que ele VAI pegar no futuro, com certeza) é um inferno.

Repito: estamos aqui para ajudar, e ajudar é mostrar a verdade completa, não a que convém. E contextualizando o grande mestre Fowler, ele criou essa frase para justificar as boas práticas, nais quais se incluem os design patterns.

J

Concordo contigo colega, como eu disse anteriormente eu não falei mal das respostas de vcs, mas como eu deduzi que o colega devia ta começando, e nessa condições bem simples, seria uma pratica correta (ao meu ver) para fazer apenas somas de juros simples. Como smp digo Caso a Caso, cada um apresentou o seu ponto de vista aqui, cabe ao colega decide qual é o melhor para o Caso dele! :slight_smile: Esse link seria o mais ideal para ele começar Como não aprender orientação a objetos: o excesso de ifs para que ele venha ter um maior entendimento e ir avançado, do que ele ter q entender tudo aquilo primeiro para depois ver como ele iria aplicar no caso dos if’s dele e então escolher qual a maneira q ele iria usar.

R

E vocês vão me desculpar, mas me apontem UM artigo de um profissional de respeito no mercado que diga que encadeamento de IFs é uma boa prática.

Esse tipo de argumento se chama “falácia do apelo à autoridade”.

uma coisa é falar que ele pode fazer assim no começo. Outra é falar que é boa prática.

Boa prática deve ser seguida desde o começo. Não existe algo como “boa prática para iniciantes” e “boa prática para seniores”. O ponto que eu estou colocando é o simples encadeamento de if’s não pode ser considerado má prática sem antes avaliar o contexto no qual foi usado. Da mesma maneira, o uso indiscriminado de padrões de projeto não é uma boa prática, aplicar um padrão onde ele não se encaixa traz mais dificuldades do que benefícios. Enfim, foi justamente para evitar essa discussão sobre o sexo dos anjos que eu pedi para o @sidneydemoraes postar um exemplo de como
ele aplicaria o Strategy ou o CoR neste caso.

P
O problema é que o padrão switch é porcamente implementado em linguagens como Java e c#. Mas em linguagem mais modernas você pode usá-lo. Por exemplo, em swift:

switch days {

case 05:

case 610:

case 1115:

case 1620:

case 2125:

case 2630:

default:

}
J

Também pensei nisso mas o fato de adicionar uma nova regra seja ela numa classe nova ou já existente não muda o fato que é necessário compilar o pacote.

P

Me parece overkill visto que em nenhum momento foi dito que o conjunto de condições precisa se atualizado de maneira independente.

J

Na minha opinião também achei, se for somente para algo simples q nem o colega apresentou, não é necessário fazer uma implementação tão “complexa”, vai depender do caso de uso

Criado 21 de janeiro de 2016
Ultima resposta 28 de jan. de 2016
Respostas 27
Participantes 11