Não tem setId, pois esse campo é atribuido internamente.
O ambiente externo não pode atribuir valor para ele, somente consultar.
Como eu faria para recuperar ou persistir esse campo em um DAO e no Hibernate ?
Mesmo que não use Hibernate, pode fazer alguma coisa com reflection. E não é a mesma coisa que usar setters. Persistência é um problema que precisa ser resolvido, mas não é por causa dele que você precisa ferrar o resto hehe
J
jprogrammer
Mas nestes casos se a segurança do JVM não permitir que os atributos sejam acessados ?
Tem alguma coisa nesse sentindo Security…Alguma coisa que eu não lembro.
Novamente, não sou nenhum expert em patterns, mas ActiveRecord + IoC cheira bem para mim.
louds
Voce pode usar métodos e atributos package protected e colocar classes auxiliares de persistencia no mesmo pacote dos teus objetos de domínio.
J
jprogrammer
Essa ideia é muito boa.
Fica a mais elegante e menos gambiarrenta.
Mas eu poderia ter vários DAOs para diferentes tipos de dados.
Como eu lidaria com isso ?
Colocaria todos os DAOs dentro do mesmo package da classes de negócio ?
Mas o caminho é por aí mesmo…
louds
Ou você pode usar um pouco de mágica com reflection, o ruim é que você perde a tipagem forte do java.
J
jprogrammer
Tive uma ideia vejam se fica tosca
teste.funcionarioclassFuncionarioDAO{protectedfinalsetId(Funcionariofunc,intid){func.setId(id);}}classFuncionario{privateintid;setId(intid){}publicgetId(){}}teste.dataclassDAOFactory{FuncionarioDAOgetFuncionarioDAO(){}}classFuncionarioHibernateDAOextendsteste.funcionario.FuncionarioDAO{// nao precisa fazer nada de diferente}classFuncionarioSqlDAOextendsteste.funcionario.FuncionarioDAO{publicFuncionarioconsultar(){Funcionariof=newFuncionario();setId(f,1);}}
J
jprogrammer
Nessas horas é que eu vejo que é melhor deixar dados e operaçoes tudo na mesma classe.
Se a classe Funcionario se persistisse esse problema não ocorreria.
Mas como criar uma classe de negócios que se auto-persista e ainda permita diversos mecanismos de persistencia ?
louds
jprogrammer:
Nessas horas é que eu vejo que é melhor deixar dados e operaçoes tudo na mesma classe.
Se a classe Funcionario se persistisse esse problema não ocorreria.
Mas como criar uma classe de negócios que se auto-persista e ainda permita diversos mecanismos de persistencia ?
O livro do GOF explica State e Strategy muito bem, leitura recomendada.
F
fabio.patricio
Louds,
Me diz uma coisa, essa classe FuncionarioPersistenceStrategy tu instanciaria dentro da propria classe Funcionario ou usaria do tipo de DI pra isso?
Ps.: Eu ando fazendo isso num sistema aqui e nao tinha me dado conta do padrao.
]['s
louds
Fabio, fica a seu gosto e necessidade
Normalmente, eu pelo menos, tenho uma classe enumerando as implementações mais freqüêntes e uns helpers de uma Strategy.
kuchma
louds:
...
O livro do GOF explica State e Strategy muito bem, leitura recomendada.
Essa estrategia eh legal, pois apenas as camadas adjacentes comunicam-se entre si, mas ainda assim as classes de persistencia precisam obter/armazenar dados na classe de modelo. E ai vem o problema de ter gets/sets apenas para isso. Poderiamos fazer as classes de persistencia extender do modelo ou vice-versa, mas nao acho isso muito elegante.
Deparei-me com essa situacao essa semana: estou criando um modelo sem gets/sets, MAS na hora de puxar os dados da fonte tem essa encrenca. Nao posso utilizar Hibernate.
Ou seja - a solucao mais viavel parece ser criar gets/sets com acesso default/package e deixar as classes de persistencia e modelo no mesmo pacote. Voces veem alguma outra solucao?
A questao pode ser resumida em (IMHO): preciso dar acesso aos campos internos da classe, mas apenas para um caso especifico e excepcional (persistencia).
Marcio Kuchma
kuchma
Gosto de usar uma factory simples e, pra ganhar flexibilidade, mover os nomes das implementacoes para um properties externo (de preferencia fora do pacote principal, pra nao precisar redistribuir/fazer redeploy quando precisamos mudar alguma coisa).
Em projetos sem limitacoes e que voce pode fazer as coisas sem medo de ser feliz, IoC pode ser uma boa (evita esse trampinho tosco de instanciar as classes dinamicamente e tal, apesar de ser coisa que se faz apenas uma vez).
Marcio Kuchma
_fs
kuchma:
…MAS na hora de puxar os dados da fonte tem essa encrenca. Nao posso utilizar Hibernate.
Hibernate não precisa de getters e setters.
kuchma
LIPE:
kuchma:
…MAS na hora de puxar os dados da fonte tem essa encrenca. Nao posso utilizar Hibernate.
Hibernate não precisa de getters e setters.
Exato. Se eu pudesse utiliza-lo, o problema estaria resolvido. CQD. :mrgreen:
Marcio Kuchma
_fs
Ah, confundi causa com consequencia no seu post
J
jprogrammer
Adorei essa estratégia bem interessante.
A instaciação pode ser via factory ?
Mas e o problema dos campos privados, como o mecanismo de persistencia vai exergar os atributos privados ?
Seria interessante que cada tipo de mecanismo estivesse pacotes diferentes.
kuchma
jprogrammer:
Adorei essa estratégia bem interessante.
A instaciação pode ser via factory ?
Sim. Essa eh a funcao dela.
jprogrammer:
Mas e o problema dos campos privados, como o mecanismo de persistencia vai exergar os atributos privados ?
Seria interessante que cada tipo de mecanismo estivesse pacotes diferentes.
Sem colocar gets/sets publicos ou utilizar estrategias heterodoxas com reflection nao vejo solucao. Alguem? :roll:
Marcio Kuchma
_fs
Injeta via IoC
E quanto aos campos private, usa Hibernate ou faz alguma coisa nojentinha com reflection ou alguma coisa assustadora com CGLib ou BCel ou faz como o cara sugere aqui:
J
jprogrammer
E se o mecanismo de persistencia extendesse de uma classe abstrata do mesmo pacote da classe persisitida ao invés de uma interface.
E nessa classe tivesse métodos acessores para a classe a ser persistida.
Para mim parece melhor do que o normal mas não entendo por que não usar Hibernate @.@
J
jprogrammer
É pro caso de não usar.
Devemos estar preparados para tudo, não é por isso que não usaria.
Ninguém é louco.
Esse é ponto que sempre coloco.
_fs
Entendo isso perfeitamente. Nesse caso eu aplicaria a mesma solução que o Hibernate, alterando o bytecode em runtime, o que não é tão complicado assim. Mas já que está prontinho pra usar …
Alguém pode se perguntar: para que essa merda toda? Posso colocar os getters e setters só para a camada de persistência funcionar e não chamá-los nunca.
Mas aí não fica bonitão né?
Thiago_Senna
Deixe-me ver se eu entendi. Isso quer dizer que seu eu criar a seguinte classe abaixo, ela é perfeitamente válida para ser persistida com o Hibernate?
E com CGLib dá para fazer isso e muito mais cuidado @.@
kuchma
Vou investigar isso pra ver o grau de complexidade. Se nao for limitado pelo mecanismo de seguranca da VM pode ser otimo.
LIPE:
Alguém pode se perguntar: para que essa merda toda? Posso colocar os getters e setters só para a camada de persistência funcionar e não chamá-los nunca.
Mas aí não fica bonitão né?
Exatamente. Sem contar que eh deprimente aquele monte de gets/sets no Outline do Eclipse. Polui muito o visual. :XD:
Sobre o Hibernate, como voces ja falaram, ele nao resolve todos os problemas (persistencia nao-SGBD, p.ex.). Ah, e nao precisamos de recomendacao de outro mecanismo de persistencia. Apenas de como resolver esse problema de falta de elegancia no modelo.
Marcio Kuchma
kuchma
Uma outra coisa boba que estive pensando hoje de manha a caminho do trabalho…
E se as implementacoes de persistencia devolvessem um Map, que a classe de modelo utilizasse para se auto-popular? Seria uma especie de “contrato” entre as partes: o modelo apenas aceita uma entrada tipo Map enquanto que todas as implementacoes de persistencia devolvem como produto final o Map citado. Isso para carregar os dados. Para salvar, processo inverso.
MAS, com isso perde-se a verificacao de tipos. Sem contar os trocentos efeitos colaterais nao-previstos na minha sonolencia matutina - aguardo as criticas.
Enquanto isso vamos olhar a CGLib…
Marcio Kuchma
_fs
Muito tenso isso cara, ainda mais com objetos aninhados. Sei que há o commons-beanUtils, mas … dor hehe prefiro colocar os métodos mais próximos à classe.
J
jprogrammer
Para usar esse negócio doido de CgLib é melhor usar HashMap.
Já pensei nisso o problema é com o hibernate.
Como vou persistir com o hibernate usando HashMap.
A tipagem talvez não seria o probelma, pois isso fica interno.
Alguém sabe ?
_fs
Hibernate suporta isso, leia a documentação do 3.0. Na verdade você pode mapear os dados para qualquer coisa que bem entender hehe
J
jprogrammer
Aí não vira uma gambi medonha.
O ideal é o hibernate persistir a classe em si, não o hashmap.
Já que o phillip deu a ideia de criar um factory dos domains model objects, por que não criar várias implementações.
Um para cada persistencia.
Seria tosco isso ?
louds
Usar um map para isso seria um desastre, com direito performance deprimente e manutenção infernal.
A questão é que java não possui um mecanismo claro de persistencia na linguagem, e isso exige que toda e qualquer solução tenha um pouco de “gambiarra” ou seja complexa o suficiente para não valer a pena.
Sinceramente, hibernate/EJB3.0/ORMxyz usando atributos privados me parece o mais próximo do ideal que pode se conseguir com java.
Isso falando de persistencia relacional, claro.
kuchma
jprogrammer:
Aí não vira uma gambi medonha.
O ideal é o hibernate persistir a classe em si, não o hashmap.
Nao sei se eu perdi o fio da meada, mas o problema existe NAO utilizando o Hibernate. Com Hibernate voce pode persistir os atributos privados mesmo (ou seja la o que for que voce queira utilizar :D).
Marcio Kuchma
J
jprogrammer
Equanto utilizar o hibernate não temos mais dúvidas.
Mas vamos supor que a persistencia é não relacional.
Porque o hashmap traz perda de performance tão grande ?
Thiago_Senna
Usando o hashmap você fica dependente do desempenho do algoritmo de classificação que você esta implementando mo método hashcode de suas classes persistentes.
Talvez seja isso? É isso mesmo?
Abraços!
Thiago
J
jprogrammer
Pegando embalo com o shoes…
E a possibilidade de ter várias implementações
abstractclassFuncionario{privateintid;protectedvoidsetId(intid){//omite codigo }publicintgetCodigo(){}publicvoidsalvar(){if(id==0){}// validacao e regras de negocio}}classFuncionarioHibernateextendsFuncionario{publicvoidsalvar(){setId(geraId());super.salvar();session.save(this);}}classFuncionarioOutraCoisaextendsFuncionario{publicvoidsalvar(){setId(geraId());super.salvar();}}classFuncionarioFactory{publicFuncionariogetFuncionario(){returnnewFuncionarioHibernate();}}Funcionariof=FuncionarioFactory.getgetFuncionario();f.salvar();
_fs
Na minha opinião é muito mais limpo que DAOs. E fica melhor ainda com IoC ao invés de factories.
Mas aí acho que deve doer para controlar transações e evitar a proliferação de chamadas ao banco. Spring ajuda nisso?
J
jprogrammer
Não vejo porque isso traria muitas chamadas ao banco.
Posso ter um factory global e controlar conexao e transação a partir dele.
Mas o que eu acho esquisito de classes que tem métodos de negócios é quando eu tenho agregação.
Tá estranho sim! Não seria melhor que dentro do método salvar de funcionario tivesse uma chamada para salvar o departamento?
louds
Hmm, isso depende de como você quer implementar a semântica de cascateamento.
Se salvar o funcionario implica em salvar o departamento, sim.
Eu acho que manter o código que faz pensistencia no mesmo lugar que está o negocio uma caca.
E se a implementação de persistencia ficar toda separada em um objeto separado e se usar agregação/herança para dar acesso a esses dados no modelo.
O código não ficar mais claro com isso já que java não suporta herança múltipla nem visibilidade de herança (herança privada do c++ faz muita falta ).
J
jprogrammer
No caso não estou salvando o departamento, apenas estou mostrando que ao agregar a classe Departamento a Funcionario o método de salvar
departamento também fica disponível.
Esse é o assunto do outro tópico.
Pelo conceito OO as operaçoes devem ficar juntas com os dados.
Se quisermos programar OO deve ficar mais ou menos parecido com isso.
Estão vendo como é difícil programar OO com relacional.
Várias coisas não se batem. São duas coisas que não se encaixam.
O pessoal meteu o pau no artigo da java magazine.
editado:
Tem outra coisa na classes que fazem as operações.
Os métodos de consulta.
É muito estranho criar uma instancia para depois obter instancias.
O ideal seria usar métodos estáticos para consulta.
Só que a herança já quebra.
Pois há somente “ocultação” não sobreposição.
ex:
classPersistentFuncionacio{privateintxxx;privateStringyyy;//Setter/getters com bound properties}classFuncionario{privatefinalPersistentFuncionaciof=newPersistentFuncionacio();//ou via construtorpublicdoublesalarioLíquito(){returnf.getSalarioBruto*(1-f.getDescontos());}}
Para que isso? Bom, usando bound properties evitamos precisar chamar save/update explicitamente e delete em alguns casos. Além disso toda lógica e dados para falar com o banco de dados fica em lugar só.
J
jprogrammer
E se eu quiser acessar diretamente um atributo que é pesistível como Nome (por ex) teria que duplicar sua declaração nas duas classes não é.
J
jprogrammer
Pensei nisso. Vejam se é tosco !
packageteste.funcionario;abstractclassFuncionario{protectedvoidsetId(intid);publicintgetId(){returnthis.id};publicvoidsalvar(){// regras de negocio}}abstractclassFuncionarioFactory{publicabstractFuncionariocreateNew();publicabstractFuncionariofind(intid);publicstaticfinalFuncionarioFactorygetInstance(){returnnewteste.funcionario.jdbc.FuncionariosJDBCFactory();}}packageteste.funcionario.jdbc;classFuncionariosJDBCFactoryextendsFuncionarioFactory{publicFuncionariocreateNew(){returnnewFuncionarioJDBC();}publicFuncionariofind(intid){ResultSetrs=....FuncionarioJDBCf=newFuncionarioJDBC();f.setId(rs.getInt("ID");}}classFuncionarioJDBCextendsFuncionario{protectedvoidsetId(intid){super.setId(id)}publicvoidsalvar(){setId(geraId());super.salvar();insertinto....}}FuncionarioFactoryfc=FuncionarioFactory.getInstance();Funcionariof=fc.find(1);// faz de conta que temf.setNome("Maria");f.salvar();