é verdade que minha maneira de implementar com 17 ifs em um metodo esta errado?
Meu codigo tem muito if, meu chefe disse que ta errado, é verdade?
80 Respostas
é verdade que minha maneira de implementar com 17 ifs em um metodo esta errado?Não é uma boa prática.
O melhor é você definir e repensar seu método.
Esse livro é muito bom para quem precisa desse tipo de coisa: Use a Cabeça - Orientação a Objeto.
nao é errado se fosse errado nao existia IF…
mas a alternativa é usar SWITCH…
;]
http://www.tiexpert.net/programacao/java/switch-case-default.php
nao é errado se fosse errado nao existia IF…
mas a alternativa é usar SWITCH…
Mais alguém precisa estudar orientação à objetos…
http://c2.com/cgi/wiki?SwitchStatementsSmell
Não é EXATAMENTE errado, mas com certeza não é uma boa prática… o código tem que ser auto explicativo, a leitura dele deve ser fluida… como dizem por ai: “Qualquer um faz código que um computador entenda, mas apenas bons profissionais fazem código que pessoas entendem”… ou algo semelhante…
Assiste esse vídeo, é um pequeno resumo do livro Clean Code do Uncle Bob… vai abrir um pouco sua visão sobre isso:
entao posso usar o swtich break no lugar dos 17 ifs? é melhor?
17 ifs? Você ta testando o que?
Com certeza deve haver uma lógica mais apropriada e simples para seu código.
Tá… tá errado.
Posta o código aqui e fale o que ele faz, que a gente pode ajudar melhor.
Certamente esse seu codigo precisa de uma refatoração .
Sugiro o livro do Martin Fowler Refatoração
Trocar if por swtich não ira resolver o problema.
Realmente códigos com muitos if, não são nem um pouco “elegantes”.
Você deve estudar bem Orientação a Objetos, seja em java, c++, ou qualquer outra linguagem.
Entender o que é acoplamento estático e dinâmico, ou seja saber aproveitar do mecanismo de polimorfismo que linguagens orientadas a objetos
oferecem.
Após estar fluente nos conceitos básicos de OO, ler sobre padrões de projetos, existe muitos livros sobre o assunto, e pode ter certeza
que ira escrever códigos de qualidade.
nao é errado se fosse errado nao existia IF…
mas a alternativa é usar SWITCH…Mais alguém precisa estudar orientação à objetos…
http://c2.com/cgi/wiki?SwitchStatementsSmell
Não comentei que eu iria fazer 17 verificações de condições no Switch apenas comentei que é uma alternativa que
tem outro modo de fazer verificações com estrutura condicional.
Eu não faria isso, de alguma outra forma eu pensaria nem que fosse 3h para tentar minimizar o máximo possível de
código.
Até pq não sei oq ele ta tentando fazer, se é programação estruturada ou orientação a objetos, nao tem como falar
pra usar POO sendo qe nao sei… seria mais facil ele postrar o código…
;]
Essas perguntas estão meio estranhas, kkkkkk!!!
Não comentei que eu iria fazer 17 verificações de condições no Switch apenas comentei que é uma alternativa que
tem outro modo de fazer verificações com estrutura condicional.Eu não faria isso, de alguma outra forma eu pensaria nem que fosse 3h para tentar minimizar o máximo possível de
código.Até pq não sei oq ele ta tentando fazer, se é programação estruturada ou orientação a objetos, nao tem como falar
pra usar POO sendo qe nao sei… seria mais facil ele postrar o código…;]
Mesmo que fosse programação estruturada, ainda cheira mal 17 ifs seguidos. Geralmente você pode resolver melhor usando alguma estrutura associativa, ponteiros, ou outras coisas similares.
Não comentei que eu iria fazer 17 verificações de condições no Switch apenas comentei que é uma alternativa que
tem outro modo de fazer verificações com estrutura condicional.Eu não faria isso, de alguma outra forma eu pensaria nem que fosse 3h para tentar minimizar o máximo possível de
código.Até pq não sei oq ele ta tentando fazer, se é programação estruturada ou orientação a objetos, nao tem como falar
pra usar POO sendo qe nao sei… seria mais facil ele postrar o código…;]
Mesmo que fosse programação estruturada, ainda cheira mal 17 ifs seguidos. Geralmente você pode resolver melhor usando alguma estrutura associativa, ponteiros, ou outras coisas similares.
Ou simplesmente verificar a possibilidade de usar o padrão Strategy. Inclusive, o próprio ViniGodoy apresentou um exemplo de leitura e compreensão simples.
Dá uma olhada: http://www.guj.com.br/java/55885-como-nao-utilizar-if-ou-switch#293436
Uma dica Maria, tente pensar mais orientado a objetos, parece que tudo está muito estruturado na sua cabeça. Analise com calma seu código, pode haver melhores alternativas.
Uma dica é utilizar-se de recursos pré estabelecidos, como um check style.
O PMD é uma ótima ferramenta.
Em geral, as ferramentas de check style conseguem auxiliar em casos como este, com muitas verificações lógicas em um método, excesso de linhas, falta de padronização, falhas ao atender as convenções de nomenclatura e especificações do Java.
Dá trabalho, mas é bem interessante e útil.
A regra geral que eu uso é tentar manter métodos tão curtos e objetivos quanto possível.
Fazendo isso você percebe que a reusabilidade de código vira algo natural.
Uma função deveria fazer somente uma coisa, se suas funções fazem mais do que isso, pode ser uma boa ideia repensá-las.
Um macete pra conseguir isso é você tentar nomear a função, se for difícil pensar em um nome pra dizer o que ela faz, ela provavelmente está fazendo mais do que uma coisa.
(Todas as dicas que dei aqui eu li no livro Clean Code)
Pra saber se um código precisa ser refatorado eu olho para o teste unitário. Qt mais complexo o teste, mais o método precisa ser refatorado. =]
O nome do livro já diz tudo.
se for encadeado, máximo de 2 ou 3 ifs… se nao for encadeado, só pensar em outra maneira de colocar seu código como usando switch, recursividade sei la…
17 ifs ta errado… imagina a manutenção disso depois 
Pra saber se um código precisa ser refatorado eu olho para o teste unitário. Qt mais complexo o teste, mais o método precisa ser refatorado. =]Se a pessoa não sabe que 17 ifs é uma péssima prática nem imagino como ficariam os testes… Acho que 35 métodos para cada método testado… -_-’’
= ]
=]
Estou tentando fazer com que ele entenda o problema.
a converça ta boa e o codigo ta em falta…
uma vez eu li num forum…
deve ta errado o ingles mas é isso ae…
Tb recomendo o livro Clean Code.
Contudo, há situações, em q vão haver vários ifs, e nem por isso significaria má prática.
Tb recomendo o livro Clean Code.Sério? Qual?Contudo, há situações, em q vão haver vários ifs, e nem por isso significaria má prática.
Eu não sou tão xiita quanto ao número de ifs num código, e apesar de 17 ser bem alto, é uma prática bem comum ao validar Forms HTML que vem com muitos dados.
O que recomendo mesmo seria separar esses ifs em vários métodos separados, cada um com sua especialidade. Por exemplo:
// dentro de uma classe de nota fiscal
validaNotaFiscal {
validaDadosBasicos
validaRemetente
validaDestinatario
validaItensDaNota
validaTransportadora
validaInformaçõesComplementares
}
E cada um deles tem mais métodos de validação (CFOP, descontos dos itens), e, claro, os ifs para tratar cada pedacinho.
Outra recomendação é fazer teu código com TinyTypes, e deixar que eles cuidem de suas próprias validações e conversões.
Tb recomendo o livro Clean Code.Sério? Qual?Contudo, há situações, em q vão haver vários ifs, e nem por isso significaria má prática.
O André não tá errado. Nem sempre vc vai poder trabalhar com objetos.
Em todo o caso, sugiro o autor do post procurar um artigo chamado “if bom é if morto” e “Strategy” pra solucionar sua dúvida.
Novamente, sério? Qual?Tb recomendo o livro Clean Code.Sério? Qual?Contudo, há situações, em q vão haver vários ifs, e nem por isso significaria má prática.
O André não tá errado. Nem sempre vc vai poder trabalhar com objetos.
Em todo o caso, sugiro o autor do post procurar um artigo chamado “if bom é if morto” e “Strategy” pra solucionar sua dúvida.
Qual o motivo se justifica a não usar algum pattern e usar toneladas de ifs independentes de objetos/strings?
Estou perguntando numa boa. Atualmente não imagino.
Novamente, sério? Qual?
Qual o motivo se justifica a não usar algum pattern e usar toneladas de ifs independentes de objetos/strings?Estou perguntando numa boa. Atualmente não imagino.
Em algum momento vc pode ter que classificar em que tipo de objeto se enquadra um dado que acaba de chegar. Nessa hora vc vai precisar usar if. Vc, nem eu podemos imaginar a situação melhor agora porque isso depende da lógica de negócio. Vas vou supor uma bem simples…
o usuário vai se cadastrar em algum lugar e dependendo da idade dele eu vou colocar ele em uma classe diferente:
if( dadosDoUsuario.idade < 18 )
{
os dados vão para o objeto a
}
else if( dadosDoUsuario.idade >= 18 && dadosDoUsuario.idade<55 )
{
os dados vão para o objeto b
}
else if( dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 )
{
os dados vão para o objeto c
}
else
{
os dados vão pro limbo
}
Você sempre terá um algoritmo que evita ninhos de IF.
enum EtapaDaVida {
JOVEM(18),
ADULTO(55),
IDOSO(120);
int idadeMaxima;
private EtapaDaVida(int idade){
this.idadeMaxima = idade;
}
}
class User {
int idade;
}
public class Example {
public static void main(String[] args) {
Map<EtapaDaVida, List<User>> grupos = new HashMap<EtapaDaVida, List<User>>();
for(EtapaDaVida etapa: EtapaDaVida.values()){
grupos.put(etapa, new ArrayList<User>());
}
List<User> listaASeparar = ...;
for (User user : listaASeparar) {
for(EtapaDaVida etapa: EtapaDaVida.values()){
if(user.idade < etapa.idadeMaxima){
grupos.get(etapa).add(user);
break;
}
}
}
}
}
Eu também compartilho a opinião que if cheira mal.
Pode reparar, a maioria das gambiarras tem um if no meio… 
Você está tentando resolver aquele problema do arquivo-texto com mãe, neta etc. que você tinha mostrado com um monte de ifs?
Parece ser o caso para um algoritmo recursivo.
É que mesmo que você ponha 17 ifs, se você tiver um arquivo com mais de 3 níveis, o seu programa vai acabar quebrando porque não esperava isso.
Problemas que envolvem estruturas de dados em formato de árvore às vezes requerem algoritmos recursivos.
Você sempre terá um algoritmo que evita ninhos de IF.enum EtapaDaVida { JOVEM(18), ADULTO(55), IDOSO(120); int idadeMaxima; private EtapaDaVida(int idade){ this.idadeMaxima = idade; } } class User { int idade; } public class Example { public static void main(String[] args) { Map<EtapaDaVida, List<User>> grupos = new HashMap<EtapaDaVida, List<User>>(); for(EtapaDaVida etapa: EtapaDaVida.values()){ grupos.put(etapa, new ArrayList<User>()); } List<User> listaASeparar = ...; for (User user : listaASeparar) { for(EtapaDaVida etapa: EtapaDaVida.values()){ if(user.idade < etapa.idadeMaxima){ grupos.get(etapa).add(user); break; } } } } }Eu também compartilho a opinião que if cheira mal.
Pode reparar, a maioria das gambiarras tem um if no meio… :)
Bem legal seu codigo.
Como vc faria se mudasse um pouquinho?
if( dadosDoUsuario.idade < 18 )
{
os dados vão para o objeto a
}
else if( dadosDoUsuario.idade >= 18 && dadosDoUsuario.idade<55 )
{
os dados vão para o objeto b
}
else if( dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 || dadosDoUsuario.numeroFilhos>2 )
{
os dados vão para o objeto c
}
else
{
os dados vão pro limbo
}
Já eu, não acredito que seja todo o tipo de classificação que possa ser resumida.
Após uma refatoração… o novo exemplo (caso alguém queira dar uma analisada) 
Obs: não estou entrando no mérito do que é melhor ou pior… é apenas um exemplo
enum EtapaDaVida {
JOVEM(18),
ADULTO(55),
IDOSO(120),
HIGHLANDER(Integer.MAX_VALUE);
int idadeMaxima;
private EtapaDaVida(int idade){
this.idadeMaxima = idade;
}
public static EtapaDaVida get(int idade){
for (EtapaDaVida etapa : values()) {
if(idade <= etapa.idadeMaxima){
return etapa;
}
}
throw new RuntimeException("resultado inesperado");
}
public static EtapaDaVida get(Date data){
return get(Utils.getIdade(data));
}
}
class Usuario{
Date nascimento;
}
public class Example {
public static void main(String[] args) {
Map<EtapaDaVida, List<Usuario>> grupos = new HashMap<EtapaDaVida, List<Usuario>>();
for(EtapaDaVida etapa: EtapaDaVida.values()){
grupos.put(etapa, getListaUsuarios());
}
//aqui é onde viria o ninho de ifs
for (Usuariousuario : getListaUsuarios()) {
EtapaDaVida etapa1 = EtapaDaVida.get(usuario.nascimento);
grupos.get(etapa1).add(usuario);
}
}
public static List<Usuario> getListaUsuarios() {
return ...;
}
}
class Utils {
public static int getIdade(Date data){
Calendar hoje = Calendar.getInstance();
Calendar nascimento = Calendar.getInstance();
nascimento.setTime(data);
int idade = hoje.get(Calendar.YEAR) - nascimento.get(Calendar.YEAR);
nascimento.set(Calendar.YEAR, hoje.get(Calendar.YEAR));
if(nascimento.compareTo(hoje) > 0){
//nao fez aniversario esse ano
idade--;
}
return idade;
}
}
Edit Coloquei a situação errada .. era para ser OR no lugar do AND.. deixa aqui esse como exemplo de qualquer forma
Condição: dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 && dadosDoUsuario.numeroFilhos>2
public static void main(String[] args) {
Map<EtapaDaVida, List<Usuario>> grupos = new HashMap<EtapaDaVida, List<Usuario>>();
for(EtapaDaVida etapa: EtapaDaVida.values()){
grupos.put(etapa, new ArrayList());
}
//aqui é onde viria o ninho de ifs
for (Usuario usuario : getListaUsuarios()) {
EtapaDaVida etapa1 = EtapaDaVida.get(usuario.nascimento);
grupos.get(etapa1).add(usuario);
}
//separar essa condição: dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 && dadosDoUsuario.numeroFilhos>2
List<Usuario> usuariosAdultosComMaisDeDoisFilhos = new ArrayList<Usuario>();
usuariosAdultosComMaisDeDoisFilhos.addAll(grupos.get(EtapaDaVida.ADULTO));
for (Iterator<Usuario> iterator = usuariosAdultosComMaisDeDoisFilhos.iterator(); iterator.hasNext();) {
Usuario usuario = iterator.next();
if(usuario.numeroFilhos <= 2){
iterator.remove();
}
}
}
Condição: dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 || dadosDoUsuario.numeroFilhos>2public static void main(String[] args) { Map<EtapaDaVida, List<Usuario>> grupos = new HashMap<EtapaDaVida, List<Usuario>>(); for(EtapaDaVida etapa: EtapaDaVida.values()){ grupos.put(etapa, getListaUsuarios()); } //aqui é onde viria o ninho de ifs for (Usuario usuario : getListaUsuarios()) { EtapaDaVida etapa1 = EtapaDaVida.get(usuario.nascimento); grupos.get(etapa1).add(usuario); } //separar essa condição: dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 || dadosDoUsuario.numeroFilhos>2 List<Usuario> usuariosAdultosComMaisDeDoisFilhos = new ArrayList<Usuario>(); usuariosAdultosComMaisDeDoisFilhos.addAll(grupos.get(EtapaDaVida.ADULTO)); for (Iterator<Usuario> iterator = usuariosAdultosComMaisDeDoisFilhos.iterator(); iterator.hasNext();) { Usuario usuario = iterator.next(); if(usuario.numeroFilhos <= 2){ iterator.remove(); } } }
Desculpa, mas agora acho que esse remove ai virou gambiarra.
Claro que sempre é bom utilizar as boas técnicas, mas não existe bala de prata.
Dependendo do tempo, do que o cliente pedir e de como a informação vier, não vai ter como escapar.
Desculpa, mas agora acho que esse remove ai virou gambiarra.na boa? Ainda prefiro assim do que aninhar 300 ifs.
Claro que sempre é bom utilizar as boas técnicas, mas não existe bala de prata.
Dependendo do tempo, do que o cliente pedir e de como a informação vier, não vai ter como escapar.
Desculpe, mas ainda assim penso que não existe motivo para 17 ifs seguidos…
Nova arquitetura, agora suporta qualquer tipo de condição. As outras estruturas, não coloquei aqui para não ficar lotando…
class Usuario {
Date nascimento;
int numeroFilhos;
}
enum Classificacao {
A(new ClassificadorA()),
B(new ClassificadorB()),
C(new ClassificadorC()),
LIMBO(new ClassificadorLimbo());
Classificador classificador;
Classificacao(Classificador classificador){
this.classificador = classificador;
}
public static Classificacao get(Usuario usuario) {
for (Classificacao c : values()) {
if(c.classificador.isClassificacao(c, usuario)){
return c;
}
}
throw new RuntimeException("resultado inesperado");
}
}
interface Classificador {
public boolean isClassificacao(Classificacao c, Usuario usuario);
}
class ClassificadorA implements Classificador{
public boolean isClassificacao(Classificacao c, Usuario usuario) {
return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.JOVEM;
}
}
class ClassificadorB implements Classificador{
public boolean isClassificacao(Classificacao c, Usuario usuario) {
return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.ADULTO;
}
}
class ClassificadorC implements Classificador{
public boolean isClassificacao(Classificacao c, Usuario usuario) {
return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.IDOSO || usuario.numeroFilhos > 2;
}
}
class ClassificadorLimbo implements Classificador{
public boolean isClassificacao(Classificacao c, Usuario usuario) {
return true;
}
}
public class Example2 {
public static void main(String[] args) {
Map<Classificacao, List<Usuario>> grupos = new HashMap<Classificacao, List<Usuario>>();
for(Classificacao etapa: Classificacao.values()){
grupos.put(etapa, new ArrayList());
}
//aqui é onde viria o ninho de ifs
for (Usuario usuario : getListaUsuarios()) {
Classificacao classificacao = Classificacao.get(usuario);
grupos.get(classificacao).add(usuario);
}
}
public static ArrayList<Usuario> getListaUsuarios() {
return new ArrayList<Usuario>();
}
}
Eu não sou tão xiita quanto ao número de ifs num código, e apesar de 17 ser bem alto, é uma prática bem comum ao validar Forms HTML que vem com muitos dados. O que recomendo mesmo seria separar esses ifs em vários métodos separados, cada um com sua especialidade. Por exemplo:E cada um deles tem mais métodos de validação (CFOP, descontos dos itens), e, claro, os ifs para tratar cada pedacinho.// dentro de uma classe de nota fiscal validaNotaFiscal { validaDadosBasicos validaRemetente validaDestinatario validaItensDaNota validaTransportadora validaInformaçõesComplementares }Outra recomendação é fazer teu código com TinyTypes, e deixar que eles cuidem de suas próprias validações e conversões.
mais se eu usar metodos nao vou ter que por ainda ifs?? ? exemplo
validaNotaFiscal {
if("mae"){
validaDadosBasicos
validaRemetente
}
if ("filha"){
validaDestinatario
}
if("neta"){
validaItensDaNota
}
if("bisneta"){
validaTransportadora
validaInformaçõesComplementares}
}
acho que isso e uma arvore, me falaram no ultimo post que abri.
Condição: dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 || dadosDoUsuario.numeroFilhos>2public static void main(String[] args) { Map<EtapaDaVida, List<Usuario>> grupos = new HashMap<EtapaDaVida, List<Usuario>>(); for(EtapaDaVida etapa: EtapaDaVida.values()){ grupos.put(etapa, getListaUsuarios()); } //aqui é onde viria o ninho de ifs for (Usuario usuario : getListaUsuarios()) { EtapaDaVida etapa1 = EtapaDaVida.get(usuario.nascimento); grupos.get(etapa1).add(usuario); } //separar essa condição: dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 || dadosDoUsuario.numeroFilhos>2 List<Usuario> usuariosAdultosComMaisDeDoisFilhos = new ArrayList<Usuario>(); usuariosAdultosComMaisDeDoisFilhos.addAll(grupos.get(EtapaDaVida.ADULTO)); for (Iterator<Usuario> iterator = usuariosAdultosComMaisDeDoisFilhos.iterator(); iterator.hasNext();) { Usuario usuario = iterator.next(); if(usuario.numeroFilhos <= 2){ iterator.remove(); } } }Desculpa, mas agora acho que esse remove ai virou gambiarra.
Claro que sempre é bom utilizar as boas técnicas, mas não existe bala de prata.
Dependendo do tempo, do que o cliente pedir e de como a informação vier, não vai ter como escapar.
A sintaxe de Java pode ficar um pouco verbosa por falta de recursos da linguagem.. O mais interessante da analise aqui, é a arquitetura resultante e como podemos contornar ifs aninhados..
Veja que se Java possuísse closures, o código podeira ficar assim:
usuariosAdultosComMaisDeDoisFilhos.retain {
it.numeroFilhos > 2;
}
Acho que o exemplo usando a nova arquitetura (exemplo com Classificadores) é melhor para resolver situações onde a condição pode ser personalizada de qualquer maneira.
Como a condição mudou para 2 variáveis (inicialmente era apenas uma) a solução anterior não era exatamente adequada. E então, esse algoritmo acabou resultando em um aproveitamento da primeira arquitetura, ao invés de uma refatoração.
Apesar de ser um exemplo acadêmico, essa problemática abre questões para várias discussões. :)
meu codigo e esse aqui
@Override
public Object lerArquivoTXTPrepararObjetosParaVirarXML_arvore() {
mae_VO mae = new mae_VO();
filha_VO filha = new filha_VO();
neta_VO neta = new neta_VO();
binesta_VO binesta = new binesta_VO();
try {
Scanner arquivo = new Scanner(new File("C:\\Projeto Revistas\\catalogacao_2013.log"));
while (arquivo.hasNext()) {
String linha = arquivo.nextLine();
// coisas que estao no começo
if (linha.contains("Revifilhaa Mãe") && linha.contains("Início da Execução")) {
mae.setDataFinal(linha);
mae.setDataInicial(linha);
mae.setDescricao(linha);
mae.setHoraFinal(linha);
mae.setHoraInicio(linha);
mae.setId(linha);
if (linha.contains("erro")) {
neta.setfilhaatus(Enumfilhaatus.ERRO);
} else if (linha.contains("atual")) {
neta.setfilhaatus(Enumfilhaatus.ATUAL);
} else
neta.setfilhaatus(Enumfilhaatus.U2013);
}
if (linha.contains("Revifilhaa Filha") && linha.contains("Início da Execução")) {
filha.setDataFinal(linha);
filha.setDataInicial(linha);
filha.setDescricao(linha);
filha.setHoraFinal(linha);
filha.setHoraInicio(linha);
filha.setId(linha);
if (linha.contains("erro")) {
neta.setfilhaatus(Enumfilhaatus.ERRO);
} else if (linha.contains("atual")) {
neta.setfilhaatus(Enumfilhaatus.ATUAL);
} else
neta.setfilhaatus(Enumfilhaatus.U2013);
}
if (linha.contains("Revifilhaa Neta") && linha.contains("Início da Execução")) {
neta.setDataFinal(linha);
neta.setDataInicial(linha);
neta.setDescricao(linha);
neta.setHoraFinal(linha);
neta.setHoraInicio(linha);
neta.setId(linha);
if (linha.contains("erro")) {
neta.setfilhaatus(Enumfilhaatus.ERRO);
} else if (linha.contains("atual")) {
neta.setfilhaatus(Enumfilhaatus.ATUAL);
} else
neta.setfilhaatus(Enumfilhaatus.U2013);
}
if (linha.contains("Revifilhaa Bisneta") && linha.contains("Início da Execução")) {
binesta.setDataFinal(linha);
binesta.setDataInicial(linha);
binesta.setDescricao(linha);
binesta.setHoraFinal(linha);
binesta.setHoraInicio(linha);
binesta.setId(linha);
if (linha.contains("erro")) {
neta.setfilhaatus(Enumfilhaatus.ERRO);
} else if (linha.contains("atual")) {
neta.setfilhaatus(Enumfilhaatus.ATUAL);
} else
neta.setfilhaatus(Enumfilhaatus.U2013);
}
// coisas que estao no final
if (linha.contains("Revista Mãe") && linha.contains("Executado com")) {
mae.getLifilhaaSuites().add(filha);
filha = new filha_VO();
}
if (linha.contains("Revista Filha") && linha.contains("Executado com")
&& linha.contains("2013")) {
filha.getLifilhaanetas().add(neta);
neta = new neta_VO();
}
if (linha.contains("Revista Bisneta") && linha.contains("Executado com")) {
neta.getLifilhaabinestas().add(binesta);
binesta = new binesta_VO();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return mae;
}
É… o problema não é só os 17 ifs…
É melhor trancar esse tópico,pelo que eu to vendo vai gerar flames comparados aos de Java versus PHP.
Nova arquitetura, agora suporta qualquer tipo de condição. As outras estruturas, não coloquei aqui para não ficar lotando..class Usuario { Date nascimento; int numeroFilhos; } enum Classificacao { A(new ClassificadorA()), B(new ClassificadorB()), C(new ClassificadorC()), LIMBO(new ClassificadorLimbo()); Classificador classificador; Classificacao(Classificador classificador){ this.classificador = classificador; } public static Classificacao get(Usuario usuario) { for (Classificacao c : values()) { if(c.classificador.isClassificacao(c, usuario)){ return c; } } throw new RuntimeException("resultado inesperado"); } } interface Classificador { public boolean isClassificacao(Classificacao c, Usuario usuario); } class ClassificadorA implements Classificador{ public boolean isClassificacao(Classificacao c, Usuario usuario) { return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.JOVEM; } } class ClassificadorB implements Classificador{ public boolean isClassificacao(Classificacao c, Usuario usuario) { return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.ADULTO; } } class ClassificadorC implements Classificador{ public boolean isClassificacao(Classificacao c, Usuario usuario) { return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.IDOSO || usuario.numeroFilhos > 2; } } class ClassificadorLimbo implements Classificador{ public boolean isClassificacao(Classificacao c, Usuario usuario) { return true; } } public class Example2 { public static void main(String[] args) { Map<Classificacao, List<Usuario>> grupos = new HashMap<Classificacao, List<Usuario>>(); for(Classificacao etapa: Classificacao.values()){ grupos.put(etapa, new ArrayList()); } //aqui é onde viria o ninho de ifs for (Usuario usuario : getListaUsuarios()) { Classificacao classificacao = Classificacao.get(usuario); grupos.get(classificacao).add(usuario); } } public static ArrayList<Usuario> getListaUsuarios() { return new ArrayList<Usuario>(); } }
Esse aqui ficou muito bom!
A sintaxe de Java pode ficar um pouco verbosa por falta de recursos da linguagem.. O mais interessante da analise aqui, é a arquitetura resultante e como podemos contornar ifs aninhados.
Se ficar verboso de mais, a chance da gambiarra ocorrer aumenta.
na boa? Ainda prefiro assim do que aninhar 300 ifs.Desculpe, mas ainda assim penso que não existe motivo para 17 ifs seguidos...
Isso depende. Eu não vi o fonte do autor do post. Se o patrão dele disse que é possivel melhorar, eu acredito. Provavelmente as condicionais que ele está usando são simples.
Quanto o problema dos IFs serem SEMPRE retirados não concordo pelos motivos que eu já citei.
Pessoal só tá expressando idéias e opiniões… É normal pessoas diferentes terem opiniões diferentes…
Ninguém aqui está brigando…
Temos que aprender a conversar e respeitar as opiniões (como está ocorrendo aqui) ao invés de ficar trancando tópicos por medo de gerar flames…
Acho ainda que a discussão aqui, gera um resultado saudável… até para quem está lendo o fórum… Iniciantes por exemplo, podem ver exemplos de casos onde existem ifs, outros casos onde foi montada uma arquitetura, e até uma refatoração… É extremamente difícil achar exemplos assim na internet…
Por falar nisso… nem sei o motivo de trancarem tópicos só porque está “flamando”… Povo quer discutir… deixa discutir… heheheh
PS: Java é melhor que PHP. kkkk
Pessoal só tá expressando idéias e opiniões… É normal pessoas diferentes terem opiniões diferentes…
Ninguém aqui está brigando…
Temos que aprender a conversar e respeitar as opiniões (como está ocorrendo aqui) ao invés de ficar trancando tópicos por medo de gerar flames…
Por falar nisso… nem sei o motivo de trancarem tópicos só porque está “flamando”… Povo quer discutir… deixa discutir… heheheh
PS: Java é melhor que PHP. kkkk
Também acho o java melhor,mas é melhor falar baixo pros fanboy não se sentirem ofendidos.
Pessoal só tá expressando idéias e opiniões… É normal pessoas diferentes terem opiniões diferentes…
Ninguém aqui está brigando…
Temos que aprender a conversar e respeitar as opiniões (como está ocorrendo aqui) ao invés de ficar trancando tópicos por medo de gerar flames…
Acho ainda que a discussão aqui, gera um resultado saudável… até para quem está lendo o fórum… Iniciantes por exemplo, podem ver exemplos de casos onde existem ifs, outros casos onde foi montada uma arquitetura, e até uma refatoração… É extremamente difícil achar exemplos assim na internet…
Por falar nisso… nem sei o motivo de trancarem tópicos só porque está “flamando”… Povo quer discutir… deixa discutir… heheheh
PS: Java é melhor que PHP. kkkk
1+
Pessoal só tá expressando idéias e opiniões… É normal pessoas diferentes terem opiniões diferentes…
Ninguém aqui está brigando…
Temos que aprender a conversar e respeitar as opiniões (como está ocorrendo aqui) ao invés de ficar trancando tópicos por medo de gerar flames…
Acho ainda que a discussão aqui, gera um resultado saudável… até para quem está lendo o fórum… Iniciantes por exemplo, podem ver exemplos de casos onde existem ifs, outros casos onde foi montada uma arquitetura, e até uma refatoração… É extremamente difícil achar exemplos assim na internet…
Por falar nisso… nem sei o motivo de trancarem tópicos só porque está “flamando”… Povo quer discutir… deixa discutir… heheheh
PS: Java é melhor que PHP. kkkk
o GUJ tá ficando ruim pelo exagero.
Já ví moderador aqui falar de coisas totalmente fora da TI e trancar tópicos só por desviar um pouco do assunto.
PS: Não… PHP é bem mais legal! Huahuahuahua
Gostei das suas idéias. As vezes agente acaba usando IFs porque não consegue visualizar forma melhor.
voce faria diferente como ??? ?
Quanto o problema dos IFs serem SEMPRE retirados não concordo pelos motivos que eu já citei.Uma coisa é ter ifs, outra coisa é ter 17…
voce faria diferente como ??? ?Ele já fez…
Novamente, sério? Qual?
Qual o motivo se justifica a não usar algum pattern e usar toneladas de ifs independentes de objetos/strings?Estou perguntando numa boa. Atualmente não imagino.
Em algum momento vc pode ter que classificar em que tipo de objeto se enquadra um dado que acaba de chegar. Nessa hora vc vai precisar usar if. Vc, nem eu podemos imaginar a situação melhor agora porque isso depende da lógica de negócio. Vas vou supor uma bem simples…
o usuário vai se cadastrar em algum lugar e dependendo da idade dele eu vou colocar ele em uma classe diferente:
if( dadosDoUsuario.idade < 18 ) { os dados vão para o objeto a } else if( dadosDoUsuario.idade >= 18 && dadosDoUsuario.idade<55 ) { os dados vão para o objeto b } else if( dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 ) { os dados vão para o objeto c } else { os dados vão pro limbo }
esse caso seu da pra usar um switch bem bonitão…
pode até ser que exista situações que exigem várias verificações que não podem ser colocadas num switch mas nesse caso, a boa prática recomenda MUDAR o jeito que está fazendo
Imagina dar manutenção num código com 17 ifs? vc vai procurar 1 por 1 toda vez q for mudar algo? e se tiver que tirar algo? ou colocar algo q depende de uma condição que está ali? ia encadear dentro dos IFs? se envolver threads então…
Algumas vezes deve-se repensar na estratégia sim e evitar isso… fazer como o Bruno Laturner falou por exemplo de colocar as verificações em métodos… desse modo, seria mais facil uma manutenção no código depois… ou pode-se usar recursividade, switch, bibliotecas de auxilio, sei la…
Cara se tem uma coisa que eu realmente to esperando no Java 8,é o suporte a lambda expressions, que com certeza vai retirar bastante ifs dos códigos.
meu codigo e esse aqui@Override public Object lerArquivoTXTPrepararObjetosParaVirarXML_arvore() { mae_VO mae = new mae_VO(); filha_VO filha = new filha_VO(); neta_VO neta = new neta_VO(); binesta_VO binesta = new binesta_VO(); try { Scanner arquivo = new Scanner(new File("C:\\Projeto Revistas\\catalogacao_2013.log")); while (arquivo.hasNext()) { String linha = arquivo.nextLine(); // coisas que estao no começo if (linha.contains("Revifilhaa Mãe") && linha.contains("Início da Execução")) { mae.setDataFinal(linha); mae.setDataInicial(linha); mae.setDescricao(linha); mae.setHoraFinal(linha); mae.setHoraInicio(linha); mae.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Filha") && linha.contains("Início da Execução")) { filha.setDataFinal(linha); filha.setDataInicial(linha); filha.setDescricao(linha); filha.setHoraFinal(linha); filha.setHoraInicio(linha); filha.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Neta") && linha.contains("Início da Execução")) { neta.setDataFinal(linha); neta.setDataInicial(linha); neta.setDescricao(linha); neta.setHoraFinal(linha); neta.setHoraInicio(linha); neta.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Bisneta") && linha.contains("Início da Execução")) { binesta.setDataFinal(linha); binesta.setDataInicial(linha); binesta.setDescricao(linha); binesta.setHoraFinal(linha); binesta.setHoraInicio(linha); binesta.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } // coisas que estao no final if (linha.contains("Revista Mãe") && linha.contains("Executado com")) { mae.getLifilhaaSuites().add(filha); filha = new filha_VO(); } if (linha.contains("Revista Filha") && linha.contains("Executado com") && linha.contains("2013")) { filha.getLifilhaanetas().add(neta); neta = new neta_VO(); } if (linha.contains("Revista Bisneta") && linha.contains("Executado com")) { neta.getLifilhaabinestas().add(binesta); binesta = new binesta_VO(); } } } catch (Exception e) { e.printStackTrace(); } return mae; }
o certo seria retrabalhar como voce está desenvolvendo...
pensando aqui, poderia fazer da seguinte maneira:
criar uma interface FAMILIA com os métodos que as classes possuem em comum... depois ficaria bem mais facil trabalhar fazendo algo como:
Familia mae;
Familia filha;
// etc
// while...
if ( !linha.contains("Início da Execução") ) {
// faz as coisas como "Executado com"...
continue;
}
// chegou aqui, sabe que a linha tem "Início da Execução"
checkMae(linha);
checkFilha(linha);
// etc
// dentro desses métodos, voce faz algo como:
public void checkMae(linha) {
if ( !linha.contains("Mãe") ) {
return;
}
mae = new mae_VO( linha ); // aqui dentro voce cria todos os SET
checkStatus( linha, mae ); // aqui voce checa se tem erros e usa um método do objeto passado por parametro no SET
}
NÂO É A MELHOR MANEIRA. Pensei rapidamente nisso aqui agora... Mas fica bem mais tranquilo o código e essas ideias podem abrir a sua cabeça ou do pessoal ;)
EU tenho que viajar hoje, mas ainda gostaria de deixar essa questão aberta.
Sim, entendo tudo o que dizem a respeito da facilidade da manutenção.
Mas mesmo retirando o excesso de IFs, os erros podem até se tornar mais fáceis de ocorrerem.
Eu vou mostrar isso no próximo post e gostaria de discutir isso com o pessoal aqui.
Quero saber como vcs evitam os tipos de erros e gambiarras que eu vou mostrar.
Exemplo do que ocorreu em um momento com o rogelgarcia :
if(usuario.numeroFilhos <= 2)
{
iterator.remove();
}
Ontem fui dormir remoendo o código do rogelgarcia , que achei muito legal (abre a cabeça), e tive um insight.
Uma regra geral para a retirada de excessos de IFs. É um problema “matemático”.
Assim que voltar dou o retorno aqui.
Quero saber como vcs evitam os tipos de erros e gambiarras que eu vou mostrar.TDD
Exemplo do que ocorreu em um momento com o rogelgarcia :
if(usuario.numeroFilhos <= 2) { iterator.remove(); }
[=
meu codigo e esse aqui@Override public Object lerArquivoTXTPrepararObjetosParaVirarXML_arvore() { mae_VO mae = new mae_VO(); filha_VO filha = new filha_VO(); neta_VO neta = new neta_VO(); binesta_VO binesta = new binesta_VO(); try { Scanner arquivo = new Scanner(new File("C:\\Projeto Revistas\\catalogacao_2013.log")); while (arquivo.hasNext()) { String linha = arquivo.nextLine(); // coisas que estao no começo if (linha.contains("Revifilhaa Mãe") && linha.contains("Início da Execução")) { mae.setDataFinal(linha); mae.setDataInicial(linha); mae.setDescricao(linha); mae.setHoraFinal(linha); mae.setHoraInicio(linha); mae.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Filha") && linha.contains("Início da Execução")) { filha.setDataFinal(linha); filha.setDataInicial(linha); filha.setDescricao(linha); filha.setHoraFinal(linha); filha.setHoraInicio(linha); filha.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Neta") && linha.contains("Início da Execução")) { neta.setDataFinal(linha); neta.setDataInicial(linha); neta.setDescricao(linha); neta.setHoraFinal(linha); neta.setHoraInicio(linha); neta.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Bisneta") && linha.contains("Início da Execução")) { binesta.setDataFinal(linha); binesta.setDataInicial(linha); binesta.setDescricao(linha); binesta.setHoraFinal(linha); binesta.setHoraInicio(linha); binesta.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } // coisas que estao no final if (linha.contains("Revista Mãe") && linha.contains("Executado com")) { mae.getLifilhaaSuites().add(filha); filha = new filha_VO(); } if (linha.contains("Revista Filha") && linha.contains("Executado com") && linha.contains("2013")) { filha.getLifilhaanetas().add(neta); neta = new neta_VO(); } if (linha.contains("Revista Bisneta") && linha.contains("Executado com")) { neta.getLifilhaabinestas().add(binesta); binesta = new binesta_VO(); } } } catch (Exception e) { e.printStackTrace(); } return mae; }
Olha... Pelo q sakei d seu código, pra melhorar a legibilidade tb, ao invés de só ifs, vc poderia usar com certeza "if e else if".
Novamente te pergunto, vale a pena ter esse monte de if?meu codigo e esse aqui@Override public Object lerArquivoTXTPrepararObjetosParaVirarXML_arvore() { mae_VO mae = new mae_VO(); filha_VO filha = new filha_VO(); neta_VO neta = new neta_VO(); binesta_VO binesta = new binesta_VO(); try { Scanner arquivo = new Scanner(new File("C:\\Projeto Revistas\\catalogacao_2013.log")); while (arquivo.hasNext()) { String linha = arquivo.nextLine(); // coisas que estao no começo if (linha.contains("Revifilhaa Mãe") && linha.contains("Início da Execução")) { mae.setDataFinal(linha); mae.setDataInicial(linha); mae.setDescricao(linha); mae.setHoraFinal(linha); mae.setHoraInicio(linha); mae.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Filha") && linha.contains("Início da Execução")) { filha.setDataFinal(linha); filha.setDataInicial(linha); filha.setDescricao(linha); filha.setHoraFinal(linha); filha.setHoraInicio(linha); filha.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Neta") && linha.contains("Início da Execução")) { neta.setDataFinal(linha); neta.setDataInicial(linha); neta.setDescricao(linha); neta.setHoraFinal(linha); neta.setHoraInicio(linha); neta.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Bisneta") && linha.contains("Início da Execução")) { binesta.setDataFinal(linha); binesta.setDataInicial(linha); binesta.setDescricao(linha); binesta.setHoraFinal(linha); binesta.setHoraInicio(linha); binesta.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } // coisas que estao no final if (linha.contains("Revista Mãe") && linha.contains("Executado com")) { mae.getLifilhaaSuites().add(filha); filha = new filha_VO(); } if (linha.contains("Revista Filha") && linha.contains("Executado com") && linha.contains("2013")) { filha.getLifilhaanetas().add(neta); neta = new neta_VO(); } if (linha.contains("Revista Bisneta") && linha.contains("Executado com")) { neta.getLifilhaabinestas().add(binesta); binesta = new binesta_VO(); } } } catch (Exception e) { e.printStackTrace(); } return mae; }Olha... Pelo q sakei d seu código, pra melhor a legibilidade tb, ao invés de só ifs, vc poderia usar com certeza "if e else if".
Novamente te pergunto, vale a pena ter esse monte de if?meu codigo e esse aqui@Override public Object lerArquivoTXTPrepararObjetosParaVirarXML_arvore() { mae_VO mae = new mae_VO(); filha_VO filha = new filha_VO(); neta_VO neta = new neta_VO(); binesta_VO binesta = new binesta_VO(); try { Scanner arquivo = new Scanner(new File("C:\\Projeto Revistas\\catalogacao_2013.log")); while (arquivo.hasNext()) { String linha = arquivo.nextLine(); // coisas que estao no começo if (linha.contains("Revifilhaa Mãe") && linha.contains("Início da Execução")) { mae.setDataFinal(linha); mae.setDataInicial(linha); mae.setDescricao(linha); mae.setHoraFinal(linha); mae.setHoraInicio(linha); mae.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Filha") && linha.contains("Início da Execução")) { filha.setDataFinal(linha); filha.setDataInicial(linha); filha.setDescricao(linha); filha.setHoraFinal(linha); filha.setHoraInicio(linha); filha.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Neta") && linha.contains("Início da Execução")) { neta.setDataFinal(linha); neta.setDataInicial(linha); neta.setDescricao(linha); neta.setHoraFinal(linha); neta.setHoraInicio(linha); neta.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } if (linha.contains("Revifilhaa Bisneta") && linha.contains("Início da Execução")) { binesta.setDataFinal(linha); binesta.setDataInicial(linha); binesta.setDescricao(linha); binesta.setHoraFinal(linha); binesta.setHoraInicio(linha); binesta.setId(linha); if (linha.contains("erro")) { neta.setfilhaatus(Enumfilhaatus.ERRO); } else if (linha.contains("atual")) { neta.setfilhaatus(Enumfilhaatus.ATUAL); } else neta.setfilhaatus(Enumfilhaatus.U2013); } // coisas que estao no final if (linha.contains("Revista Mãe") && linha.contains("Executado com")) { mae.getLifilhaaSuites().add(filha); filha = new filha_VO(); } if (linha.contains("Revista Filha") && linha.contains("Executado com") && linha.contains("2013")) { filha.getLifilhaanetas().add(neta); neta = new neta_VO(); } if (linha.contains("Revista Bisneta") && linha.contains("Executado com")) { neta.getLifilhaabinestas().add(binesta); binesta = new binesta_VO(); } } } catch (Exception e) { e.printStackTrace(); } return mae; }Olha... Pelo q sakei d seu código, pra melhor a legibilidade tb, ao invés de só ifs, vc poderia usar com certeza "if e else if".
:D
Hum...
Faça a leitura do código dela, e com base "nele" diga-nos como vc o implementaria... Na teoria todos sabemos o q um monte de ifs pode significar, na prática, temos o código acima para com base nele opinar.
Abraços,
André AS.

Hum…
Faça a leitura do código dela, e com base “nele” diga-nos como vc o implementaria… Na teoria todos sabemos o q um monte de ifs pode significar, na prática, temos o código acima para com base nele opinar.
Abraços,
André AS.
Ei, você quem disse lá tras que monte de if pode não ser má prática. Por isso te refiz a pergunta:
Pode ser que o modo como você trate seus ifs melhore, mas eu ainda não consigo pensar em um.Tb recomendo o livro Clean Code.Sério? Qual?Contudo, há situações, em q vão haver vários ifs, e nem por isso significaria má prática.

Hum…
Faça a leitura do código dela, e com base “nele” diga-nos como vc o implementaria… Na teoria todos sabemos o q um monte de ifs pode significar, na prática, temos o código acima para com base nele opinar.
Abraços,
André AS.
Ei, você quem disse lá tras que monte de if pode não ser má prática. Por isso te refiz a pergunta:
Pode ser que o modo como você trate seus ifs melhore, mas eu ainda não consigo pensar em um.Tb recomendo o livro Clean Code.Sério? Qual?Contudo, há situações, em q vão haver vários ifs, e nem por isso significaria má prática.
Talvez eu não tenha sido claro, vou recolocar de outra forma: Vc poderia com base no q ela nos enviou, analisar, pensar e então, enviar uma opinião factível, visto q ela é estagiária, qlq. coisa muito abstrata é possível q não assimile…
Opinei sendo objetivo com base no q ela enviou. Se ficasse falando de TDD, livros Refactoring, apenas, acho q não ajudaria ela, tanto q, ela enviou o código pra esta finalidade, avaliarmos e com base nele podermos ser mais diretos. Desculpe, mas não foi o seu caso. 
Talvez eu não tenha sido claro, vou recolocar de outra forma: Vc poderia com base no q ela nos enviou, analisar, pensar e então, enviar uma opinião factível, visto q ela é estagiária, qlq. coisa muito abstrata é possível q não assimile…
Opinei sendo objetivo com base no q ela enviou. Se ficasse falando de TDD, livros Refactoring, apenas, acho q não ajudaria ela, tanto q, ela enviou o código pra esta finalidade, avaliarmos e com base nele podermos ser mais diretos. Desculpe, mas não foi o seu caso.
![]()
Desculpa, André. Realmente não estou querendo ser chato, mas você deu sua opinião.
Você mesmo disse que uma quantidade grande de ifs pode não ser má prática, porém não disse e não exemplificou nada que justificasse sua resposta. Outros responderam com ideias e exemplos de código tornando essa discussão bastante saudável, mas eu também fiquei curioso quanto ao seu ponto de vista.
Você realmente consegue exemplificar uma situação onde a melhor solução é um encadeamento enorme de ifs?
Não alimente spammers
Só pode ser brincadeira:
if (linha.contains("Revifilhaa Mãe") && linha.contains("Início da Execução")) {
mae.setDataFinal(linha);
mae.setDataInicial(linha);
mae.setDescricao(linha);
mae.setHoraFinal(linha);
mae.setHoraInicio(linha);
mae.setId(linha);
if (linha.contains("erro")) {
neta.setfilhaatus(Enumfilhaatus.ERRO);
} else if (linha.contains("atual")) {
neta.setfilhaatus(Enumfilhaatus.ATUAL);
} else
neta.setfilhaatus(Enumfilhaatus.U2013);
}
Mas reutilize essa lógica com um método com passagem de parâmetros, os ifs tem códigos repetidos, isso é extremamente ruim pensando de forma orientada a objetos…
Oi,
Falar que algo é errado por utilizar 17 IFs é muita ignorância. O máximo é dizer que o código não está bom e que pode ser melhorado. O errado é algo que não funciona, ou algo que não condiz com o especificado.
É obvio e muito claro que um código de 17 IFs pode ser melhorado. Nenhum código é perfeito. A ideia já foi feita, agora basta melhorar a lógica.
Acho que o pessoal exagerou na codificação. E acho que muitos usuários responderam coisas absurdas para uma simples pergunta.
Quer ajuda? Pergunte. Nota-se que você é esforçado(a).
Tchauzin!
17 ifs está errado!
Assim como: get_nome() também está errado.
Pra mim, não é só código que retorna o esperado que está certo. Se retorna o resultado, mas fazendo gambiarra, pra mim está errado.
E tenho certeza que isso é errado para outros programadores experientes também.
Você liga um arame na sua fiação elétrica e a luz funciona. Tá certo? Não!
17 ifs está errado!Assim como: get_nome() também está errado.
Pra mim, não é só código que retorna o esperado que está certo. Se retorna o resultado, mas fazendo gambiarra, pra mim está errado.
E tenho certeza que isso é errado para outros programadores experientes também.Você liga um arame na sua fiação elétrica e a luz funciona. Tá certo? Não!
“Quem” diz o que está errado ou não é o compilador.
O máximo que você pode dizer é sobre o nível de abstração OO, uso de padrões e convenções.
Porém, é obvio que o código dela pode e deve ser melhorado.
uol poxa vida hein ♫♫
17 ifs,pode ser varias condições, se eu faço assim ta errado hahaha (logico que não!).Posso ter ate 30 ifs.
if(this.nomeSegurado == null) {
msg.append("<br>- Nome não preenchido");
atributos.add("nomeSegurado");
invalido = true;
}
if(this.dataNascimento == null) {
msg.append("<br>- Data de nascimento não preenchida");
atributos.add("dataNascimento");
invalido = true;
}
if(this.sexo == null) {
msg.append("<br>- Sexo não selecionado");
atributos.add("sexo");
invalido = true;
} ........
Sinceramente, eu acho que o pessoal tá muito preocupado no sintoma do que no problema em si. Na minha opinião, trocar 17 IF’s por 17 classes ou 17 métodos só quebraria a coesão do método e tornaria a leitura do código muito mais sofrida. Na prática, somente serviria para mudar a duplicação de lugar.
É impressão minha ou estão discutindo a definição de erro?
Essa definição varia de acordo com o que você queira definir. A ISO, por exemplo, chamaria uma falha de padrão de “não conformidade”.
Agora, não se enganem, não conformidades podem ser tão ou mais problemáticas do que o erro em si. Não é porque você deixou de chamar de erro, que o problema ficou menos problemático.
public Object lerArquivoTXTPrepararObjetosParaVirarXML_arvore() {
mae_VO mae = new mae_VO();
filha_VO filha = new filha_VO();
neta_VO neta = new neta_VO();
binesta_VO binesta = new binesta_VO();
try {
Scanner arquivo = new Scanner(new File("C:\\Projeto Revistas\\catalogacao_2013.log"));
while (arquivo.hasNext()) {
String linha = arquivo.nextLine();
if(linha.contains("Início da Execução")){ // coisas que estao no começo
if (linha.contains("Revifilhaa Mãe")) {
mae.setDataFinal(linha);
mae.setDataInicial(linha);
mae.setDescricao(linha);
mae.setHoraFinal(linha);
mae.setHoraInicio(linha);
mae.setId(linha);
}else if (linha.contains("Revifilhaa Filha")) {
filha.setDataFinal(linha);
filha.setDataInicial(linha);
filha.setDescricao(linha);
filha.setHoraFinal(linha);
filha.setHoraInicio(linha);
filha.setId(linha);
}else if (linha.contains("Revifilhaa Neta")) {
neta.setDataFinal(linha);
neta.setDataInicial(linha);
neta.setDescricao(linha);
neta.setHoraFinal(linha);
neta.setHoraInicio(linha);
neta.setId(linha);
}else if (linha.contains("Revifilhaa Bisneta")) {
binesta.setDataFinal(linha);
binesta.setDataInicial(linha);
binesta.setDescricao(linha);
binesta.setHoraFinal(linha);
binesta.setHoraInicio(linha);
binesta.setId(linha);
}
if (linha.contains("erro")) {
neta.setfilhaatus(Enumfilhaatus.ERRO);
} else if (linha.contains("atual")) {
neta.setfilhaatus(Enumfilhaatus.ATUAL);
} else{
neta.setfilhaatus(Enumfilhaatus.U2013);
}
}
if(linha.contains("Executado com")){// coisas que estao no final
if (linha.contains("Revista Mãe")) {
mae.getLifilhaaSuites().add(filha);
filha = new filha_VO();
}else if (linha.contains("Revista Filha") && linha.contains("2013")) {
filha.getLifilhaanetas().add(neta);
neta = new neta_VO();
}else if (linha.contains("Revista Bisneta")) {
neta.getLifilhaabinestas().add(binesta);
binesta = new binesta_VO();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return mae;
}
Bom, eu tentei remover as duplicações do código … ao invés de trocar o if por classes ou métodos eu procurei remover somente os trechos duplicados. O que eu percebi é que duplicação está nas classes VO. Reparem que elas possuem exatamente a mesma interface, caberia ai declarar uma interface comum a todas ou ainda, criar uma classe só com um campo de tipo.
Pessoal me pediu que colocasse o código comentado sobre a resolução para evitar IFS.
Abaixo do código colocarei uma explicação:
/*
* Esse sistema tem dois conceitos.
* Etapa da vida, associado a idade da pessoa.
* Classificacoes, associadas a qualquer informação da pessoa.
*
* A idéia é resolver essa problemática sugerida pelo colega Luiz Augusto Prado sem o uso de IFS:
if( dadosDoUsuario.idade < 18 )
{
os dados vão para o objeto a
}
else if( dadosDoUsuario.idade >= 18 && dadosDoUsuario.idade<55 )
{
os dados vão para o objeto b
}
else if( dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 || dadosDoUsuario.numeroFilhos>2 )
{
os dados vão para o objeto c
}
else
{
os dados vão pro limbo
}
*
*
*/
/**
* Esse enum representa as 4 etapas possíveis da vida para esse sistema.
*/
enum EtapaDaVida {
JOVEM(18),
ADULTO(55),
IDOSO(120),
HIGHLANDER(Integer.MAX_VALUE);
//um ENUM pode ter atributos
int idadeMaxima;
//que sao atribuidos através do construtor
//após atribuido, o valor é imutável (lembre-se ENUMs são imutáveis)
private EtapaDaVida(int idade){
this.idadeMaxima = idade;
}
/**
* Método que retorna a Etapa da vida para determinada idade
*/
public static EtapaDaVida get(int idade){
for (EtapaDaVida etapa : values()) { //values() = [JOVEM, ADULTO, IDOSO, HIGHLANDER]
if(idade <= etapa.idadeMaxima){
// se a idade for menor que a idade máxima da etapa significa que
// é essa a etapa relacionada a idade
return etapa;
}
}
//se não encontrar etapa relacionada com a idade retorna um erro
throw new RuntimeException("resultado inesperado");
}
/**
* Método que retorna a Etapa da vida para determinada data.
* Irá calcular quantos anos a pessoa tem através de Utils.getIdade
* @param data
* @return
*/
public static EtapaDaVida get(Date data){
return get(Utils.getIdade(data));
}
}
class Usuario {
Date nascimento;
int numeroFilhos;
}
/**
* Esse enum representa as 4 classificações do sistema.
*/
enum Classificacao {
//cada enum será construido com um classificador
A(new ClassificadorA()),
B(new ClassificadorB()),
C(new ClassificadorC()),
LIMBO(new ClassificadorLimbo());
Classificador classificador;
Classificacao(Classificador classificador){
this.classificador = classificador;
}
public boolean isClassificacao(Usuario u){
//a classificacao utiliza o classificador para determinar se o usuario faz parte dela
return classificador.isClassificacao(u); //o classificador é uma das classes implementadas abaixo
}
public static Classificacao get(Usuario usuario) {
for (Classificacao c : values()) {//values() = [A, B, C, LIMBO]
//para cada Classificacao (enum), verificamos se o usuario faz parte dela
if(c.isClassificacao(usuario)){
return c; //retorna a classificacao do usuario
}
}
throw new RuntimeException("resultado inesperado");
}
}
/**
* Interface que representa um classificador
*/
interface Classificador {
/*
* Retorna true se esse classificador considera que o usuário faz parte dele
*/
public boolean isClassificacao(Usuario usuario);
}
class ClassificadorA implements Classificador{
public boolean isClassificacao(Usuario usuario) {
return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.JOVEM;
}
}
class ClassificadorB implements Classificador{
public boolean isClassificacao(Usuario usuario) {
return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.ADULTO;
}
}
class ClassificadorC implements Classificador{
public boolean isClassificacao(Usuario usuario) {
return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.IDOSO || usuario.numeroFilhos > 2;
}
}
class ClassificadorLimbo implements Classificador{
public boolean isClassificacao(Usuario usuario) {
return true;
}
}
public class Example2 {
public static void main(String[] args) {
//monta a estrutura de dados que vai receber a distribuicao
Map<Classificacao, List<Usuario>> grupos = new HashMap<Classificacao, List<Usuario>>();
for(Classificacao etapa: Classificacao.values()){
//para cada chave (Classificacao), criamos uma nova lista
grupos.put(etapa, new ArrayList<Usuario>());
}
//aqui é onde viria o ninho de ifs
for (Usuario usuario : getListaUsuarios()) {
//retornamos a classificacao do usuario
Classificacao classificacao = Classificacao.get(usuario);
//adicionamos o ususario a classificacao correta
grupos.get(classificacao).add(usuario);
}
}
public static ArrayList<Usuario> getListaUsuarios() {
return new ArrayList<Usuario>(); //aqui seria criada a lista de usuarios a serem organizados
}
}
class Utils {
//método utilitário para retornar a idade de uma data
public static int getIdade(Date data){
Calendar hoje = Calendar.getInstance();
Calendar nascimento = Calendar.getInstance();
nascimento.setTime(data);
int idade = hoje.get(Calendar.YEAR) - nascimento.get(Calendar.YEAR);
nascimento.set(Calendar.YEAR, hoje.get(Calendar.YEAR));
if(nascimento.compareTo(hoje) > 0){
//nao fez aniversario esse ano
idade--;
}
return idade;
}
}
Não se atente ao número de linhas do código. O importante aqui é a análise da arquitetura criada. Qual a diferença entre esse código e um conjunto de ifs do ponto de vista de organização do sistema e não de esforço para criar tal solução.
Esse sistema possui dois conceitos: Etapa da vida e Classificação.
Os objetos do tipo Usuario, serão organizados em uma lista de acordo com sua classificação. Essa classificação envolve a descoberta da etapa da vida de um usuário.
Etapa da Vida
Para descobrir a etapa da vida, podemos fazer o seguinte:
EtapaDaVida ev = EtapaDaVida.get(usuario.nascimento);
A primeira questão a se notar nesse código é que existe uma estrutura que representa a etapa. É bastante diferente, de termos uma String ou int para identificar essa etapa. Veja que se não tivessemos essa estrutura, é com tipos básicos que teriamos que representar essa informação no sistema. Porém, uma String não define bem o que está sendo representado. Uma String pode conter qualquer coisa, um EtapaDaVida só pode conter etapas de vida.
Nessa solução, pegamos um conceito presente no sistema e criamos uma entidade para representar esse conceito.
Veja que se quiséssemos separar os usuários por etapa de vida, e não tivéssemos essa estrutura. Teriamos um código semelhante a esse:List<Usuario> listaJovens = new ArrayList<Usuario>();
List<Usuario> listaAdultos = new ArrayList<Usuario>();
List<Usuario> listaIdosos = new ArrayList<Usuario>();
List<Usuario> limbo = new ArrayList<Usuario>();
for (Usuario usuario : getListaUsuarios()) {
if (Utils.getIdade(usuario.nascimento) < 18) {
listaJovens.add(usuario);
} else if (Utils.getIdade(usuario.nascimento) < 55) {
listaAdultos.add(usuario);
} else if (Utils.getIdade(usuario.nascimento) < 120) {
listaIdosos.add(usuario);
} else {
limbo.add(usuario);
}
}
Map<EtapaDaVida, List<Usuario>> map = new HashMap<EtapaDaVida, List<Usuario>>();
for (Usuario usuario : getListaUsuarios()) {
EtapaDaVida etapa = EtapaDaVida.get(usuario.nascimento);
List<Usuario> list = map.get(etapa);
if(list == null){
map.put(etapa, list = new ArrayList<Usuario>());
}
list.add(usuario);
}
Podemos ainda dizer, que o segundo algoritmo nunca precisará ser modificado caso novas classificações de idade sejam adicionadas ao sistema. Basta adicionar uma nova entrada ao Enum. Diferente do primeiro caso onde o algoritmo de organização será alterado.
O Enum também facilita encontrar referencias no sistema que utilizam esse conceito.
O segundo algoritmo não possui uma sequencia de IFs para testar diversas condições. Ele possui um algoritmo que recebe uma entrada, e processa. Sem variações.
Sabe aquele erro que só acontece em determinadas condições no sistema? Então, geralmente essas condições são uma sequencia de IFs onde um caso não foi previsto. Na arquitetura proposta, não existem casos não previstos.
Classificacao
A solução dada à Classificação, é semelhante a solução da EtapaDeVida. Porém, a classificação pode conter qualquer condição. Por isso, foi criada uma interface Classificador. Cada enum Classificacao, possui um objeto dessa interface. Esse objeto, especifico do enum é capaz de dizer se determinado dado é da Classificacao ou não. No final das contas, pode-se utilizar o enum para dizer se o dado faz parte da classificacao. Por trás dos panos ele usa o classificador.
As vantagens apresentadas na EtapaDeVida também acontecem nessa situação. E ainda, se determinada condição de uma classificação mudar, é necessário mudar apenas um único ponto no sistema. Um ponto muito bem definido.
----------------------------------------------
Pegando o gancho do colega Luiz Augusto Prado, um algoritmo deve ser uma fórmula matemática. Deve-se dar um input, que retorna um output, sem determinadas condições. É como uma máquina, que devido as suas engrenagens sempre funciona, não importando a situação. Imagine a marcha de um carro, não existem ifs perguntando a posicao da alavanca para mudar a engrenagem da marcha. A alavanca está relacionada ao cambio e a modificacao da posição implica a mudança da engrenagem (sem ifs).
Com construções avançadas, onde existe uma engrenagem no seu sistema, é possível ter muito mais segurança, e afirmar com mais precisão que um sistema é robusto. Não tem ifs.. pode bater com pau que ele vai funcionar.
No dia a dia do desenvolvimento vão existir situações onde outros fatores vão importar no resultado da sua programação, principalmente o tempo. É perfeitamente normal que faça alguma solução que não seja ideal. Mas é importante saber, quando uma arquitetura pode ou precisa ser melhorada e fazer isso. Caso contrário, quando o sistema tiver já com seus anos de desenvolvimento, a zona vai ser tão grande que a manutenção fica impraticável (quem aqui conhece um sistemas desse?? rsrsrs)
----------------------------------------------
Não necessariamente a solução dos 17 ifs é a utilização de uma interface Classificação. É necessário analisar os requisitos e pensar em uma solução que seja adequada e tenha bom custo x beneficio.
Pessoal me pediu que colocasse o código comentado sobre a resolução para evitar IFS.Abaixo do código colocarei uma explicação:
/* * Esse sistema tem dois conceitos. * Etapa da vida, associado a idade da pessoa. * Classificacoes, associadas a qualquer informação da pessoa. * * A idéia é resolver essa problemática sugerida pelo colega Luiz Augusto Prado sem o uso de IFS: if( dadosDoUsuario.idade < 18 ) { os dados vão para o objeto a } else if( dadosDoUsuario.idade >= 18 && dadosDoUsuario.idade<55 ) { os dados vão para o objeto b } else if( dadosDoUsuario.idade >= 55 && dadosDoUsuario.idade<120 || dadosDoUsuario.numeroFilhos>2 ) { os dados vão para o objeto c } else { os dados vão pro limbo } * * */ /** * Esse enum representa as 4 etapas possíveis da vida para esse sistema. */ enum EtapaDaVida { JOVEM(18), ADULTO(55), IDOSO(120), HIGHLANDER(Integer.MAX_VALUE); //um ENUM pode ter atributos int idadeMaxima; //que sao atribuidos através do construtor //após atribuido, o valor é imutável (lembre-se ENUMs são imutáveis) private EtapaDaVida(int idade){ this.idadeMaxima = idade; } /** * Método que retorna a Etapa da vida para determinada idade */ public static EtapaDaVida get(int idade){ for (EtapaDaVida etapa : values()) { //values() = [JOVEM, ADULTO, IDOSO, HIGHLANDER] if(idade <= etapa.idadeMaxima){ // se a idade for menor que a idade máxima da etapa significa que // é essa a etapa relacionada a idade return etapa; } } //se não encontrar etapa relacionada com a idade retorna um erro throw new RuntimeException("resultado inesperado"); } /** * Método que retorna a Etapa da vida para determinada data. * Irá calcular quantos anos a pessoa tem através de Utils.getIdade * @param data * @return */ public static EtapaDaVida get(Date data){ return get(Utils.getIdade(data)); } } class Usuario { Date nascimento; int numeroFilhos; } /** * Esse enum representa as 4 classificações do sistema. */ enum Classificacao { //cada enum será construido com um classificador A(new ClassificadorA()), B(new ClassificadorB()), C(new ClassificadorC()), LIMBO(new ClassificadorLimbo()); Classificador classificador; Classificacao(Classificador classificador){ this.classificador = classificador; } public boolean isClassificacao(Usuario u){ //a classificacao utiliza o classificador para determinar se o usuario faz parte dela return classificador.isClassificacao(u); //o classificador é uma das classes implementadas abaixo } public static Classificacao get(Usuario usuario) { for (Classificacao c : values()) {//values() = [A, B, C, LIMBO] //para cada Classificacao (enum), verificamos se o usuario faz parte dela if(c.isClassificacao(usuario)){ return c; //retorna a classificacao do usuario } } throw new RuntimeException("resultado inesperado"); } } /** * Interface que representa um classificador */ interface Classificador { /* * Retorna true se esse classificador considera que o usuário faz parte dele */ public boolean isClassificacao(Usuario usuario); } class ClassificadorA implements Classificador{ public boolean isClassificacao(Usuario usuario) { return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.JOVEM; } } class ClassificadorB implements Classificador{ public boolean isClassificacao(Usuario usuario) { return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.ADULTO; } } class ClassificadorC implements Classificador{ public boolean isClassificacao(Usuario usuario) { return EtapaDaVida.get(usuario.nascimento) == EtapaDaVida.IDOSO || usuario.numeroFilhos > 2; } } class ClassificadorLimbo implements Classificador{ public boolean isClassificacao(Usuario usuario) { return true; } } public class Example2 { public static void main(String[] args) { //monta a estrutura de dados que vai receber a distribuicao Map<Classificacao, List<Usuario>> grupos = new HashMap<Classificacao, List<Usuario>>(); for(Classificacao etapa: Classificacao.values()){ //para cada chave (Classificacao), criamos uma nova lista grupos.put(etapa, new ArrayList<Usuario>()); } //aqui é onde viria o ninho de ifs for (Usuario usuario : getListaUsuarios()) { //retornamos a classificacao do usuario Classificacao classificacao = Classificacao.get(usuario); //adicionamos o ususario a classificacao correta grupos.get(classificacao).add(usuario); } } public static ArrayList<Usuario> getListaUsuarios() { return new ArrayList<Usuario>(); //aqui seria criada a lista de usuarios a serem organizados } } class Utils { //método utilitário para retornar a idade de uma data public static int getIdade(Date data){ Calendar hoje = Calendar.getInstance(); Calendar nascimento = Calendar.getInstance(); nascimento.setTime(data); int idade = hoje.get(Calendar.YEAR) - nascimento.get(Calendar.YEAR); nascimento.set(Calendar.YEAR, hoje.get(Calendar.YEAR)); if(nascimento.compareTo(hoje) > 0){ //nao fez aniversario esse ano idade--; } return idade; } }Não se atente ao número de linhas do código. O importante aqui é a análise da arquitetura criada. Qual a diferença entre esse código e um conjunto de ifs do ponto de vista de organização do sistema e não de esforço para criar tal solução.
Esse sistema possui dois conceitos: Etapa da vida e Classificação.
Os objetos do tipo Usuario, serão organizados em uma lista de acordo com sua classificação. Essa classificação envolve a descoberta da etapa da vida de um usuário.Etapa da Vida
Para descobrir a etapa da vida, podemos fazer o seguinte:
EtapaDaVida ev = EtapaDaVida.get(usuario.nascimento);A primeira questão a se notar nesse código é que existe uma estrutura que representa a etapa. É bastante diferente, de termos uma String ou int para identificar essa etapa. Veja que se não tivessemos essa estrutura, é com tipos básicos que teriamos que representar essa informação no sistema. Porém, uma String não define bem o que está sendo representado. Uma String pode conter qualquer coisa, um EtapaDaVida só pode conter etapas de vida.
Nessa solução, pegamos um conceito presente no sistema e criamos uma entidade para representar esse conceito.
Veja que se quiséssemos separar os usuários por etapa de vida, e não tivéssemos essa estrutura. Teriamos um código semelhante a esse:A estrutura que temos aqui são quatro listas de usuários. Com o Enum:List<Usuario> listaJovens = new ArrayList<Usuario>(); List<Usuario> listaAdultos = new ArrayList<Usuario>(); List<Usuario> listaIdosos = new ArrayList<Usuario>(); List<Usuario> limbo = new ArrayList<Usuario>(); for (Usuario usuario : getListaUsuarios()) { if (Utils.getIdade(usuario.nascimento) < 18) { listaJovens.add(usuario); } else if (Utils.getIdade(usuario.nascimento) < 55) { listaAdultos.add(usuario); } else if (Utils.getIdade(usuario.nascimento) < 120) { listaIdosos.add(usuario); } else { limbo.add(usuario); } }A estrutura que temos aqui é um mapa cuja chave representa um conceito no sistema.Map<EtapaDaVida, List<Usuario>> map = new HashMap<EtapaDaVida, List<Usuario>>(); for (Usuario usuario : getListaUsuarios()) { EtapaDaVida etapa = EtapaDaVida.get(usuario.nascimento); List<Usuario> list = map.get(etapa); if(list == null){ map.put(etapa, list = new ArrayList<Usuario>()); } list.add(usuario); }Podemos ainda dizer, que o segundo algoritmo nunca precisará sem modificado caso novas classificações de idade sejam adicionadas ao sistema. Basta adicionar uma nova entrada ao Enum. Diferente do primeiro caso onde o algoritmo de organização será alterado.
O Enum também facilita encontrar referencias no sistema que utilizam esse conceito.
O segundo algoritmo não possui uma sequencia de IFs para testar diversas condições. Ele possui um algoritmo que recebe uma entrada, e processa. Sem variações.
Sabe aquele erro que só acontece em determinadas condições no sistema? Então, geralmente essas condições são uma sequencia de IFs onde um caso não foi previsto. Na arquitetura proposta, não existem casos não previstos.
Classificacao
A solução dada a classificação é semelhante a solução da EtapaDeVida. Porém, a classificação pode conter qualquer condição. Por isso, foi criada uma interface Classificador. Cada enum Classificacao, possui um objeto dessa interface. Esse objeto, especifico do enum é capaz de dizer se determinado dado é da Classificacao ou não. No final das contas, pode-se utilizar o enum para dizer se o dado faz parte da classificacao. Por trás dos panos ele usa o classificador.
As vantagens apresentadas na EtapaDeVida também acontecem nessa situação. E ainda, se determinada condição de uma classificação mudar, é necessário mudar apenas um único ponto no sistema. Um ponto muito bem definido.
----------------------------------------------
Pegando o gancho do colega Luiz Augusto Prado, um algoritmo deve ser uma fórmula matemática. Deve-se dar um input, que retorna um output, sem determinadas condições. É como uma máquina, que devido as suas engrenagens sempre funciona, não importando a situação. Imagine a marcha de um carro, não existem ifs perguntando a posicao da alavanca para mudar a engrenagem da marcha. A alavanca está relacionada ao cambio e a modificacao da posição implica a mudança da engrenagem (sem ifs).Com construções avançadas, onde existe uma engrenagem no seu sistema, é possível ter muito mais segurança, e afirmar com mais precisão que um sistema é robusto. Não tem ifs.. pode bater com pau que ele vai funcionar.
No dia a dia do desenvolvimento vão existir situações onde outros fatores vão importar no resultado da sua programação, principalmente o tempo. É perfeitamente normal que faça alguma solução que não seja ideal. Mas é importante saber, quando uma arquitetura pode ou precisa ser melhorada e fazer isso. Caso contrário, quando o sistema tiver já com seus anos de desenvolvimento, a zona vai ser tão grande que a manutenção fica impraticável (quem aqui conhece um sistemas desse?? rsrsrs)
----------------------------------------------Não necessariamente a solução dos 17 ifs é a utilização de uma interface Classificação. É necessário analisar os requisitos e pensar em uma solução que seja adequada e tenha bom custo x beneficio.
"Poxa vida ehm uôooou". rs. :D
Apenas para completar o tópico.. O resultado do algoritmo que tem que ler o seguinte arquivo:
[18/01/2013 15:26:19] Revista Mãe => Início da Execução
[18/01/2013 15:26:19] Revista Filha => Início da Execução
[18/01/2013 15:26:19] Revista Neta => Início da Execução
[18/01/2013 15:26:19] Revista => Executando
[18/01/2013 15:26:19] Revista => Início execução
[18/01/2013 15:26:19] Revista => Valores
@.codigo = 4
@.nome = Cupom Brinde
@.tipoDeCupom = Vale
[18/01/2013 15:26:19] Revista Bisneta => Início da Execução
[18/01/2013 15:26:27] SUCESSO
[18/01/2013 15:26:28] SUCESSO
[18/01/2013 15:26:31] SUCESSO
[18/01/2013 15:26:31] SUCESSO
[18/01/2013 15:26:31] SUCESSO
[18/01/2013 15:26:32] SUCESSO
[18/01/2013 15:26:33] SUCESSO
[18/01/2013 15:26:33] Revista Bisneta => Executado com SUCESSO
Duração Total: 13s 948ms
[18/01/2013 15:26:33] Revista Bisneta => Início da Execução
[18/01/2013 15:26:33] SUCESSO
[18/01/2013 15:26:33] SUCESSO
[18/01/2013 15:26:36] SUCESSO
[18/01/2013 15:26:37] SUCESSO
[18/01/2013 15:26:38] ERRO
[18/01/2013 15:26:38] SUCESSO
[18/01/2013 15:26:38] SUCESSO
[18/01/2013 15:26:38] SUCESSO
[18/01/2013 15:26:38] Revista Bisneta => Executado com INSTABILDADE
Duração Total: 5s 469ms
[18/01/2013 15:27:48] Revista Neta => Executado com FALHA
Duração Total: 1m 28s 954ms
[18/01/2013 15:27:48] Revista Filha => Executado com FALHA
Duração Total: 1m 28s 955ms
[18/01/2013 15:27:48] Revista Mãe => Executado com FALHA
Duração Total: 1m 28s 963ms
[18/01/2013 15:26:19] Revista Mãe => Início da Execução
[18/01/2013 15:27:48] Revista Mãe => Executado com FALHA
Duração Total: 1m 28s 963ms
[18/01/2013 15:26:19] Revista Bisneta => Início da Execução
[18/01/2013 15:26:33] Revista Bisneta => Executado com SUCESSO
Duração Total: 13s 948ms
enum Status {
SUCESSO,
INSTABILDADE,
FALHA,
ERRO
}
class Revista {
String inicio;
String fim;
Status status;
String tipo;
List<Revista> filhas = new ArrayList<Revista>();
Revista parent = null;
String duracao;
@Override
public String toString() {
return toString("");
}
private String toString(String padding) {
String value = "";
if(this.parent == null){
value = padding + "root\n";
} else {
value += String.format("%s + %s %s %s %s %s%n", padding, tipo.toUpperCase(), status, duracao, inicio, fim);
}
for (Revista filha : filhas) {
value += filha.toString(padding+" ");
}
return value;
}
}
public static void main(String[] args) throws IOException {
Reader log = new FileReader("revista.txt");
List<String> lines = readLines(log);
Revista root = new Revista();
readLevel(root, lines);
System.out.println(root);
}
O que ele faz é..
1. Cria um reader para o arquivo
2. readLines: Lê as linhas do arquivo e salva em uma lista
3. Cria uma revista para ser o root (é uma revista que ficará no topo, para ser o node principal da árvore)
4. readLevel: Método recursivo que dada uma lista de linhas e uma revista. Le o conteúdo e preeche os dados (método principal do algoritmo)
5. Imprime o resultado
private static void readLevel(Revista parent, List<String> lines) {
if(lines.size() == 0){//acabou o arquivo
return;
}
String firstLine = lines.get(0); //[18/01/2013 15:26:19] (...) => Início da Execução
int level = getLevel(firstLine);//level basicamente é a identação da linha
int lastLineIndex = getCloseNode(lines, level);//[18/01/2013 15:27:48] (...) => Executado com FALHA
String lastLine = lines.get(lastLineIndex);
Status status = getStatus(lastLine); // FALHA, SUCESSO, etc
String duracao = lines.get(lastLineIndex+1).substring(level); //Duração Total: 1m 28s 963ms
String tipo = getTipo(firstLine); // Mãe, Filha, Neta Bisneta
Revista revista = new Revista(); //configura a revista com os dados extraidos
revista.parent = parent;
revista.status = status;
revista.duracao = duracao;
revista.tipo = tipo;
revista.inicio = firstLine.substring(0, 21);//[18/01/2013 15:27:48]
revista.fim = lastLine.substring(0, 21);//[18/01/2013 15:27:48]
parent.filhas.add(revista); //adiciona essa revista na revista parent
readLevel(revista, lines.subList(1, lastLineIndex)); //le o interno dessa revista
readLevel(parent, lines.subList(lastLineIndex+2, lines.size())); //le as revistas subsequentes (irmãs da variavel revista)
}
private static String getTipo(String line) {
//[18/01/2013 15:26:19] Revista Mãe => Início da Execução
// ^^^
int close = line.indexOf(" =>");
line = line.substring(0, close).trim();
int begin = line.lastIndexOf(" ");
return line.substring(begin);
}
private static Status getStatus(String statusLine) {
//[18/01/2013 15:27:48] Revista Filha => Executado com FALHA
return Status.valueOf(statusLine.substring(statusLine.trim().lastIndexOf(' ') + 1).trim());
}
/**
* Retorna a próxima linha que fecha com o nível
* Ex.:
* [18/01/2013 15:26:19] Revista Mãe => Início da Execução
* Para esse nível ^
* Retorna essa linha
* [18/01/2013 15:27:48] Revista Mãe => Executado com FALHA
* ^
*/
private static int getCloseNode(List<String> lines, int level) {
for (int i = 1; i < lines.size(); i++) {
if(getLevel(lines.get(i)) == level){
return i;
}
}
throw new RuntimeException("file inconsistent");
}
private static int getLevel(String line) {
//[18/01/2013 15:26:19] Revista Filha => Início da Execução
//retorna a posição do caracter 'R'
int lineStart = line.indexOf(']') + 2;
while(line.charAt(lineStart) == '\t'){
lineStart++;
}
return lineStart;
}
static String[] ignore = {
"(.*?)Revista =>(.*?)", //[18/01/2013 15:26:19] Revista => Início execução
"(.*?)@\\.(.*?)", // @.codigo = 4
"\\[(.*?)\\]\\s+[A-Z]+\\s?", //[18/01/2013 15:26:36] SUCESSO
};
/**
* Lê as linhas do arquivo ignorando as não desejadas
*/
public static List<String> readLines(Reader log) throws IOException {
List<String> lines = new ArrayList<String>();
//TODO CLOSE
BufferedReader in = new BufferedReader(log);
String linha = null;
OUTER:
while((linha = in.readLine()) != null){
for (String pattern : ignore) {//ignora as linhas não desejadas
if(linha.matches(pattern)){
continue OUTER;
}
}
lines.add(linha);
}
return lines;
}
O código é recursivo e genérico. Suporta quantos níveis forem de filhos e não importa o nome da Revista.
Saída do programa (no meu arquivo coloquei duas maes para testar melhor o algoritmo)root
+ MÃE FALHA Duração Total: 1m 28s 963ms [18/01/2013 15:26:19] [18/01/2013 15:27:48]
+ FILHA FALHA Duração Total: 1m 28s 955ms [18/01/2013 15:26:19] [18/01/2013 15:27:48]
+ NETA FALHA Duração Total: 1m 28s 954ms [18/01/2013 15:26:19] [18/01/2013 15:27:48]
+ BISNETA SUCESSO Duração Total: 13s 948ms [18/01/2013 15:26:19] [18/01/2013 15:26:33]
+ BISNETA INSTABILDADE Duração Total: 5s 469ms [18/01/2013 15:26:33] [18/01/2013 15:26:38]
+ MÃE SUCESSO Duração Total: 1m 28s 963ms [19/01/2013 15:26:19] [19/01/2013 15:27:48]
+ FILHA FALHA Duração Total: 1m 28s 955ms [19/01/2013 15:26:19] [19/01/2013 15:27:48]
+ NETA FALHA Duração Total: 1m 28s 954ms [19/01/2013 15:26:19] [19/01/2013 15:27:48]
+ BISNETA SUCESSO Duração Total: 13s 948ms [19/01/2013 15:26:19] [19/01/2013 15:26:33]
+ BISNETA INSTABILDADE Duração Total: 5s 469ms [19/01/2013 15:26:33] [19/01/2013 15:26:38]
Última situação… agora que o cérebro está fervendo com tantas informações… um exemplo mais simples:
Como calcular a idade de uma data (quantos anos se passaram)
Para resolver essa questão propus o seguinte método (atualizado)
public static int getIdade(Date data){
//burocracia
Calendar hoje = Calendar.getInstance();
Calendar nascimento = Calendar.getInstance();
nascimento.setTime(data);
//diferenca de anos
int idade = hoje.get(Calendar.YEAR) - nascimento.get(Calendar.YEAR);
//verificar aniversario
nascimento.set(Calendar.YEAR, hoje.get(Calendar.YEAR));
if(nascimento.get(Calendar.DAY_OF_YEAR) > hoje.get(Calendar.DAY_OF_YEAR)){
//nao fez aniversario esse ano
idade--;
}
return idade;
}
Basicamente, o que esse algoritmo faz é verificar a diferença em anos de hoje até a data passada como parametro.
Depois ele pega a data passada como parametro, e passa para o ano atual. Teremos duas datas no mesmo ano.
Se não tiver passado o aniversário, temos que remover 1 da idade.
Matemática pura.
Agora, veja essa outra solução de outro site:
Calendar dob = Calendar.getInstance();
dob.setTime(dateOfBirth);
Calendar today = Calendar.getInstance();
int age = today.get(Calendar.YEAR) - dob.get(Calendar.YEAR);
if (today.get(Calendar.MONTH) < dob.get(Calendar.MONTH)) {
age--;
} else if (today.get(Calendar.MONTH) == dob.get(Calendar.MONTH)
&& today.get(Calendar.DAY_OF_MONTH) < dob.get(Calendar.DAY_OF_MONTH)) {
age--;
}
Fonte: http://stackoverflow.com/questions/1116123/how-do-i-calculate-someones-age-in-java
É desnecessário fazer tantos testes sendo que a matemática resolve…
EDITED.
Apenas para completar o tópico.. O resultado do algoritmo que tem que ler o seguinte arquivo: ...[18/01/2013 15:26:19] Revista Mãe => Início da Execução [18/01/2013 15:26:19] Revista Filha => Início da Execução [18/01/2013 15:26:19] Revista Neta => Início da Execução [18/01/2013 15:26:19] Revista => Executando [18/01/2013 15:26:19] Revista => Início execução ...
Liked.
Olá pessoa! Desculpem-me pela demora.
Vou tentar mostar alguns erros que já passei aqui, mas antes vou postar um código:
Classe ICondicao:
package testeiforstrategy;
interface ICondicao<T>
{
public boolean execute(T p);
}
class Parametros
{
String nome;
int idade;
int QtFilhos;
}
class CondicaoA implements ICondicao<Parametros>
{
public boolean execute(Parametros p)
{
if(p.idade<18)
{
System.out.println("O usuário \""+ p.nome +"\" é JOVEM");
return true;
}
return false;
}
}
class CondicaoB implements ICondicao<Parametros>
{
public boolean execute(Parametros p)
{
if(p.idade<55)
{
System.out.println("O usuário \""+ p.nome +"\" é ADULTO");
return true;
}
return false;
}
}
class CondicaoC implements ICondicao<Parametros>
{
public boolean execute(Parametros p)
{
if( p.idade<120 || p.QtFilhos>0)
{
System.out.println("O usuário \""+ p.nome +"\" é IDOSO ou já possui Filhos");
return true;
}
return false;
}
}
class CondicaoD implements ICondicao<Parametros>
{
public boolean execute(Parametros p)
{
System.out.println("O usuário \""+ p.nome +"\" é Muito Idoso ou já possui Filhos");
return true;
}
}
As classes TesteIfOrStrategy1 e TesteIfOrStrategy2 são a mesma coisa, mas
Classe de teste TesteIfOrStrategy1 aproxima-se mais do feito pelo rogelgarcia
package testeiforstrategy;
enum EnumCondicoes
{
A(new CondicaoA()),
B(new CondicaoB()),
C(new CondicaoC()),
D(new CondicaoD());
ICondicao condicao;
EnumCondicoes(ICondicao condicao)
{
this.condicao = condicao;
}
public static <T> boolean isCondicao(T p)
{
for (EnumCondicoes c : values())
{
if(c.condicao.execute(p))
{
return true;
}
}
throw new RuntimeException("resultado inesperado");
}
}
/**
* @author Luiz A. Prado
* sobre assunto discutino no link:
* http://www.guj.com.br/java/291925-meu-codigo-tem-muito-if-meu-chefe-disse-que-ta-errado-e-verdade
*
*/
public class TesteIfOrStrategy1
{
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
Parametros p = new Parametros();
p.nome = "Luiz";
p.idade = 66;
p.QtFilhos = 3;
EnumCondicoes.isCondicao(p);
}
}
classe de teste TesteIfOrStrategy2 é o que prefiro utilizar
package testeiforstrategy;
import java.util.ArrayList;
import java.util.List;
class Seletor
{
List condicoes;
Seletor()
{
condicoes = new ArrayList<ICondicao>();
}
public void add(ICondicao c)
{
condicoes.add(c);
}
public <T> boolean isCondicao(T p)
{
for (Object c : condicoes)
{
if(((ICondicao)c).execute(p))
{
return true;
}
}
throw new RuntimeException("resultado inesperado");
}
}
/**
* @author Luiz A. Prado
* sobre assunto discutino no link:
* http://www.guj.com.br/java/291925-meu-codigo-tem-muito-if-meu-chefe-disse-que-ta-errado-e-verdade
*
*/
public class TesteIfOrStrategy2
{
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
Parametros p = new Parametros();
p.nome = "Luiz";
p.idade = 66;
p.QtFilhos = 3;
Seletor s = new Seletor();
s.add(new CondicaoA());
s.add(new CondicaoB());
s.add(new CondicaoC());
s.add(new CondicaoD());
s.isCondicao(p);
}
}
Eu acredito que o uso de IFs ou Strategy não estão errados. É mais uma questão de gosto.
Mas se for para falar de erros, vou mostrar 2 exemplos que costumam me dar trabalho no Strategy:
-
ORDEM: No arquivo TesteIfOrStrategy1 entre as linhas 4 e 9 e na TesteIfOrStrategy2 entre as linhas 47 e 53 são inseridos as condicionais. Se vc errar esta ordem ou esquecer de inserir uma das condições, o programa roda, mas com o funcionamento incorreto. E neste caso seria melhor que o programa parasse de funcionar quando dessemos pauladas.
-
FRAGMENTACAO DA LOGICA: No arquivo ICondição eu reuní todas as classes (metodos) das condicionais, para facilitar a comparação das condicionais. Em uma empresa onde trabalhei isso não acontecia. Cada classe ficava em um arquivo separado. Isso não tem como acontecer quando utilizamos IFs seguidos. A análise era muito chata porque a condicional de uma dependia da outra. Olhe o codigo exemplo abaixo para entender o que quero dizer.
Isso é só um exemplo. O mesmo problema poderia ocorrer com outros tipos de objetos ou combinando operadores:
if(i<10)
{
...
}
else if(i=10)
{
...
}
else if(i<10)
{
...
}
Se quisermos mudar de 10 para 20, teremos que ficar atentos em 3 condicionais. Quando as condicionais estão espalhadas em vários arquivos, estes erros ficam chatos de se controlar. Nesse ultimo caso, eu acharia mais fácil de analisar as condicionais em uma sequencia de ifs.
Quero saber como vcs evitam os tipos de erros e gambiarras que eu vou mostrar.TDD
Exemplo do que ocorreu em um momento com o rogelgarcia :
if(usuario.numeroFilhos <= 2) { iterator.remove(); }
[=
Se eu escrevesse um codigo de 300 ifs seguidos sem erros, o TDD acusaria a má esconha do pattern?
Erro o JUnit apontaria, má pratica existem plugins para isso.Quero saber como vcs evitam os tipos de erros e gambiarras que eu vou mostrar.TDD
Exemplo do que ocorreu em um momento com o rogelgarcia :
if(usuario.numeroFilhos <= 2) { iterator.remove(); }
[=Se eu escrevesse um codigo de 300 ifs seguidos sem erros, o TDD acusaria a má esconha do pattern?
Quais os plugins que vc usa para evitar as más práticas?
Atualmente uso o Intellij e ele faz essa análise.
Erro o JUnit apontaria, má pratica existem plugins para isso.
Quais os plugins que vc usa para evitar as más práticas?
Com o eclipse utilizava o findbug e o pmd.
Erro o JUnit apontaria, má pratica existem plugins para isso.
Quais os plugins que vc usa para evitar as más práticas?
Atualmente uso o Intellij e ele faz essa análise.
Com o eclipse utilizava o findbug e o pmd.
Ainda para o Eclipse você tem o Checkstyle, o JDepend e o Metrics.