Aos "Anti IF's de plantão

Estou aqui querendo eliminar alguns(varios) if’s, estava dando uma olhada neste post, excelente post do ViniGodoy por sinal, mas não consegui captar e adaptar ao meu problema.

Meu problema é o seguinte tenho uma tela com varios checkboxes, estes check’s servem para definir a criação de um arquivo TXT, eles terão efeito na geração de comandos SQL, onde de acordo com a escolha comandos serão adicionados ou excluidos, senão o metodo inteiro.

Alguma idéia elegante e bem OO??

Pode postar o código (ou parte dele) com os ifs, só para termos uma idéia melhor do que você está falando?

Muito tempo ouço dizer em eliminar os if´s, mas em determinadas situações é impossivel, programação é lógica, e o "if’ está explicitamente ligada a lógica.

Acho que eliminar completamente os ifs é impossível mesmo. Mas tem que estar atento a situação como a do post que ele linkou ali em cima. Geralmente você elimina ifs que testam contra uma mesma variável, que representa o tipo de alguma coisa. Ou seja, nas situações em que você poderia ter no lugar um switch.

Não sei qual o seu caso, más a maioria dos ifs espalhados no seu programa com a mesma intenção podem ser melhorados com factories… Pelo menos é o q eu faço…

Maus nao ter postado antes, fiquei sem net em casa(mais um modem pro pau).

É a geração do SPED Fiscal, vou tentar passar a idéia aqui.

Bom no sped existem blocos e cada bloco possui registros, alguns blocos/registros são opcionais, e eles interferem em outros blocos/registros quando são gerados ou não, eu fui la fiz meus select’s monstruosos trazendo tudo de uma vez só usando varios left joins, union all, in’s e ect.

Por exemplo no bloco 0 eu tenho o registro 0150 - Tabela de Cadastro do Participante, onde os “clientes” que aparecem no sped devem ser citados, ou seja os clientes das NF-e de entrada/saida, das compras e cupons fiscais

Outro registro é o 0190 que é a IDENTIFICACAO DAS UNIDADES DE MEDIDA, semelhante ao 0150, porem deve conter todas as unidades de medidas encontradas em nos mesmo itens citados acima.

0200 a mesma coisa, TABELA DE IDENTIFICACAO DO ITEM(PRODUTO E SERVICO) descrição dos produtos que apareceram em algum documento fiscal tambem.

Acontece que para gerar esses registros eu fiz tudo em um mesmo select(talvez eu deva mudar isto) com unionn all e tals, ai supondo que o cara desmarque o checkbox de gerar os itens de cupom fiscal, eu teria que ter os ifs, vamos a um codigo do 0190:

public List<Registro0190> getRegistro0190() throws SQLException {
        List<Registro0190> retorno = new ArrayList<Registro0190>();

        StringBuffer sql = new StringBuffer();
        sql.append("select codunid, descunid from equnidade u ");
        sql.append("where codemp = ? and codfilial = ? and (u.codunid ");
        sql.append("in( ");
        sql.append("select und.codunid from vdvenda v ");
        sql.append("left join vditvenda item on(item.codvenda = v.codvenda and item.codemp = v.codemp and item.codfilial = v.codfilial) ");
        sql.append("left join eqproduto prod on(prod.codprod = item.codprod and prod.codemp = item.codemp and prod.codfilial = item.codfilial) ");
        sql.append("left join equnidade und on(und.codunid = prod.codunid and und.codemp = prod.codemp and und.codfilial = prod.codfilial) ");
        sql.append("where v.dtemitvenda between ? and ?  and v.codemp = u.codemp and v.codfilial = u.codfilial and v.nfecstat is null and v.nfestatus not in(5,4) ");
        sql.append("and v.statusvenda not like 'C%')) ");
        sql.append("or u.codunid ");
        sql.append("in( ");
        sql.append("select und.codunid from cpcompra c ");
        sql.append("left join cpitcompra citem on(citem.codcompra = c.codcompra and citem.codemp = c.codemp and citem.codfilial = c.codfilial) ");
        sql.append("left join eqproduto cprod on(cprod.codprod = citem.codprod and cprod.codemp = citem.codemp and cprod.codfilial = citem.codfilial) ");
        sql.append("left join equnidade und on(und.codunid = cprod.codunid and und.codemp = cprod.codemp and und.codfilial = cprod.codfilial) ");
        sql.append("where c.dtentcompra between ? and ?  and c.codemp = u.codemp and c.codfilial = u.codfilial ");
        sql.append("and c.statuscompra not like 'C%'))");
        sql.append("or u.codunid ");
        sql.append("in( select red.und from reducaozitens425 red ");
        sql.append("where red.cooreducao in(select r405.posicaocrz from reducaoz400_405 r405 ");
        sql.append("where r405.dtreducao between ? and ?))");

Neste caso eu tenho tres vezes o código “u.codunid in(…)” um para cada tabela/documento, sejam compras, cupom fiscais ou nostas fiscais, e é ai que entrarão os IF’s caso o usuario resolva desrmarcar a opção de gerar cupons por exemplo, ou entao de gerar as compras, e tantos outros if’s para cada caso semelhante, ou seja ele mexendo um checkbox, vai afetar diretamente o 0150, 0190, 0200.

Sera que eu devo decompor isto em varios metodos?? Tipo getRegistro0190Compras, getRegistro0190Vendas, getRegistro0190Cupons, etc.

Pelo que eu entendi vc quer fazer com que a SQL seja dinamica certo???

Bom… um caso que realmente é interessante é o Criteria do Hibernate… ele acaba com a bagunça…Não sei se vale a pena pra vc mudar agora pq é complexo pra implementar…

Uma dica importante que li no livro do Fowler sobre arquitetura de projetos corporativos… Nunca faça mais que 3 junções (tbm acho difícil…rs…) ou seu sistema pode ficar comprometido… Se realmente precisar fazer, é necessário conversar com um DBA para analisar possíveis indices a serem criados… Fica a deixa…

Strategy serveria mais se você fosse contruir coisas completamente diferentes, como SQL de inserção de Produtos e outra para cadastro de Pessoas. Neste caso o teu programa meio que seria um parser universal, e aí sim instanciaria parsers de Produtos e de Pessoas.

A montagem em si do SQL pode deixar para algum Builder Pattern, mas a parte de passar os comandos da UI para lógica, você não tem muita escolha.

Tente fazer uma classe Diretora, como no exemplo, que receba todos os teus parâmetros de construção, e que orquestre tudo. Por dentro é capaz de ser um monte de ifs mesmo.

[quote=viniciusfaleiro]Pelo que eu entendi vc quer fazer com que a SQL seja dinamica certo???

Bom… um caso que realmente é interessante é o Criteria do Hibernate… ele acaba com a bagunça…Não sei se vale a pena pra vc mudar agora pq é complexo pra implementar…

Uma dica importante que li no livro do Fowler sobre arquitetura de projetos corporativos… Nunca faça mais que 3 junções (tbm acho difícil…rs…) ou seu sistema pode ficar comprometido… Se realmente precisar fazer, é necessário conversar com um DBA para analisar possíveis indices a serem criados… Fica a deixa…
[/quote]

Colocar Hibernate/JPA nesta altura do campeonato estou descartando, é uma app grande e ja desenvolvida(não por mim), colocar JPA apenas por causa do sped, na verdade este cara ai é o FreedomERP, que estou usando e acreditem voces não iriam querer mexer no código dele :shock: Eu estou apenas adicionando a geração do SPED com o que tenho na mão, sem mexer muito.

[quote=Bruno Laturner]Strategy serveria mais se você fosse contruir coisas completamente diferentes, como SQL de inserção de Produtos e outra para cadastro de Pessoas. Neste caso o teu programa meio que seria um parser universal, e aí sim instanciaria parsers de Produtos e de Pessoas.

A montagem em si do SQL pode deixar para algum Builder Pattern, mas a parte de passar os comandos da UI para lógica, você não tem muita escolha.

Tente fazer uma classe Diretora, como no exemplo, que receba todos os teus parâmetros de construção, e que orquestre tudo. Por dentro é capaz de ser um monte de ifs mesmo.[/quote]

Eu tenho a classe SpedController que recebe da view uma classe SpedFiscal, esta classe SpedFiscal contem todas as informações necessarias, como as opções dos checkboxes, o nome do File a ser salvo, a data inicial/final e etc. O SpedController se encarrega de fazer as chamadas ao SpedFiscalDAO, como o metodo que citei acima e entao escrever no Stream.