Eu também implicava com isso. Para ajudar, imagine-se usando uma collection ao invés de repositório. Se você chamar list.get() e alterar alguma informação da instância retornada, a coleção também conterá a instância com suas devidas alterações. No entanto, imagine que em algum momento na aplicação é criado uma cópia desta instância e esta sofre alterações. O equals e hashcode são os mesmos. Para a coleção, o objeto ainda é o mesmo, apesar de serem instâncias diferentes. Se vc quiser que estas alterações sejam registradas na coleção então você terá que adicionar este objeto novamente na lista para substituir a instância antiga.
Repositorio deve ser similar a uma collection inclusive nestes aspectos, em minha opinião (o que muda é que faz mais sentido definir igualdade entre as entidade à partir dos Id’s ao invés do equals). Para facilitar gosto de pensar que ao obter uma entidade do repositorio, obrigatoriamente devo adicioná-lo novamente para que o repositório saiba das alterações que ocorreram na entidade.
Não sei se fui claro, mas assim como você, eu também tenho minhas implicâncias e esta era uma delas, que ao meu ver acabou sendo diluído pelo beneficios de produtividade que posso obter usando repositorio. Espero ter ajudado!
peço qualquer desculpa se você interpretou minhas declarações como ofensa pessoal, minha intenção era somente emitir opiniões sobre o seu exemplo.
Bom vamos às tréplicas:
:arrow: com relação ao repositório, eu acho realmente estranho ele ter métodos de salvar. Eu sei que pro Evans não é assim, e que pro Nilsson também não, mas é gosto pessoal mesmo. A razão da minha implicância é que quando peço um objeto para o repositório, este objeto não deixou de existir no repositório, tanto é que as próximas consultas irão trazer o mesmo objeto. Então, por que adicionar um objeto ao repositório se este ainda tem conhecimento daquele?
Talvez porque no mundo real, sem um Hibernate, fazer os objetos se salvarem por mágica seja impossível, ou pelo menos, requer muito trabalho, daí esses metódos estão lá no repositório para não complicar muito nossas vidas. Porém, ainda não deixa de ser esquisito pra mim.
:arrow: Foi uma mancada eu ter dito que poderia usar actions como camada de serviço. Idealmente, não. E às vezes dá problema em se fazer isso. Mas tem vezes, principalmente quando as actions são POJOs e quando a ação é simples, que eu “quebro o protocolo” e faço da action a camada de serviço. Não acho isso o fim do mundo, principalmente se isso está sendo feito conscientemente. O problema fui eu em transformar a exceção em regra.
É isso.
[/quote]
Hei! De maneira alguma (e nem teria pq) levar como ofensa pessoal, hahahahahaa!!!
o topico foi criado para ser criticado mesmo… tanto é que como já disse, acatei algumas sugestões…
O ponto é: repositorios têm que ter add mesmo quando são eles a criar os objetos.
[quote=cmoscoso]
Creio que isso seja indiferente para os clientes do repositorio ja que eles dependem apenas da interface.[/quote]
Não , não dependem.Elas dependem de um contrato. Contrato é muito mais que uma interface.
Vc já usou JPA ? já pensou para que serve o merge ? Já usou o Hibernate ? já pensou porque é preciso o Session in View ?
Eu estou lendo o blog do Sérgio Taborda, especificamente sobre DAO e surgiram algumas dúvidas na parte dos repositórios:
Em relação a nomenclatura, no teu exemplo tu utiliza Repository, UsuarioRepository e UsuarioDAO. Em comparação com o artigo do Sérgio Taborda, seriam apenas nomes diferentes para:
Repository = GenericDAO
UsuarioRepository = UsuarioDAO (se existisse no exemplo passado pelo Sérgio)
UsuarioDAO = implementação do UsuarioDAO
Ou eu estou enganado? Parecem ser equivalentes. Mas aí surgiria outro ponto, que seria em relação a separação dos pacotes. Tu usa Repository no pacote aplicacao.domain.model.repository, SE ele for só uma interface para os DAOS não seria mais interessante mantê-lo em aplicacao.domain.persistence.dao?
Sim.
Repository é um objeto completamente separado do DAO. Tem interface diferente e tem proposito diferente.
Repositorios podem utilizar DAOs , mas DAOs não podem usar repositorios.
Repository = UsuarioRepository
DAO = UsuarioDAO
Implementação do DAO = JDBCUsuarioDAO (note o nome da tecnologia de persistencia no nome)
Mas não são.
DAO é um cara que recebe um parametro de pesquisa generico e executa uma API especial para retornar os dados brutos
dessa pesquisa.
Repositorio é um cara que recebe parametros especificos do dominio , criar um parametro (ou mais) que o DAO entenda
executa o método no DAO, pega o resultado, trata esse resultado e no fim devolve objetos do dominio.
O repositorio não compatilha a mesma interface que o DAO. Eles não são objetos da mesma hirarquia de classes, nem de interfaces.
Um DAO deve ser reaproveitável. Se vc não trabalha com sistemas legados isso é sempre possivel.
Nesse cenário o DAO não pertence ao codigo do seu projeto. Pertence a alguma API utilitária que vc já usou antes
e fica num pacote utilitário no mesmo nivel que um utils da vida
O repositorio depende inteiramente do dominio, e portanto da aplicação , e deve estar junto das classes de dominio como Cliente, Produto etc… (Aliás essa proximidade é desejável para poder se aproveitar do uso do modificador padrão de acesso). Ele pertence ao mesmo pacote que o modelo do dominio
Acredito que até mesmo especificar um DAO como “UsuarioDAO” possa ser de uma granulariedade dispensável. Costumo usar o DAO para abstrair persistência sem ter que conhecer implícitamente elementos do domínio.
As assinaturas podem ser a grosso modo: find(String query), persist(Object obj), delete(Object obj) e demais relacionadas.
Costumo deixar os detalhes do domínio para o repositório, eg: buscaUsuariosInativos(). Internamente o Repositorios se vira com o DAO ou qualquer outro meio para satisfazer os critério do domínio.
Acredito que até mesmo especificar um DAO como “UsuarioDAO” possa ser de uma granulariedade dispensável. Costumo usar o DAO para abstrair persistência sem ter que conhecer implícitamente elementos do domínio.
As assinaturas podem ser a grosso modo: find(String query), persist(Object obj), delete(Object obj) e demais relacionadas.
Costumo deixar os detalhes do domínio para o repositório, eg: buscaUsuariosInativos(). Internamente o Repositorios se vira com o DAO ou qualquer outro meio para satisfazer os critério do domínio. [/quote]
Sim, essa é a prática atual que é mais reutilizável. Eu faço o mesmo. Mas infelizmente o pessoal ainda não entendeu bem a diferença então escolhi não dar esse passo adicional. É verdade que com o UsuárioDAO a diferença entre ele e o Repositorio fica mais ténue e que o repositorio só faz sentido com um DAO generico, mas …baby-steps…
Sergio, muito obrigado pelas explicações mais uma vez. De antemão lhe digo que não havia visto o artigo sobre Repository no teu blog. Aliás, existe algum livro que fale sobre ele também? Não encontrei no GoF, nem no Core J2EE Patterns, mas gostaria de estudá-lo. Esses conceitos ainda são muito abstratos pra mim, uma vez que estudo eles há pouco tempo e estou começando com essas implementações só agora.
Uma pergunta, pra complementar: um framework como o Hibernate abstrai algum destes “processos”?
[quote=wagnerfrancisco]Esses conceitos ainda são muito abstratos pra mim, uma vez que estudo eles há pouco tempo e estou começando com essas implementações só agora.
Uma pergunta, pra complementar: um framework como o Hibernate abstrai algum destes “processos”?
[/quote]
Os conceitos importantes são 3: DAO , Domain Store e Repository
DAO tem duas"facetas": Temos o DAO original que servia para colocar todo o SQL e fazer a ponte entre o banco e os objetos e ao mesmo tempo era plugável. Contudo ele continha regras de negocio e não apenas mapeamento O-R
Temos o DAO atual que apenas comtêm mapeamento e é reaproveitável para vários projetos e dominios.
Nenhum dos dois impoe um ciclo de vida no objeto persistente. Aliás não existe o conceito de objeto persistente com DAO.
Este padrão tinha dois defeitos: não tinha ciclo de vida e continha logica de negocio.
O Domain Store é o padrão que adiciona ciclo de vida ao processo. Ele usa um DAO “burro” sem ciclo e completa o processo.
O Repositorio é onde fica a logica de negocio.
Então vc usa um repositório para conter regras de negocio: ou seja, consturir pesquisas especiais e usa o DAO ou o Domain Store para executar essas pesquisas. Se usa o DAO os objetos retornados são genericos demais (tipo ResulSet) e o Repositorio tem que ostraduzir para objetos do dominio. Se usa o Domain Store ele ja faz essa tradução e de quebra controla o estado do objeto.
O Hibernate é uma implementação de Domain Store, assim como o JPA. Domain Store é um JEE Core Pattern
Repositorio é um padrão introduzido pelo Fowler e depois adotado pelo pessoal do DDD. O repositorio do Fowler não contém métodos de edição (save, etc) só de pesquisa. Tem uma pequena explicação no site de http://martinfowler.com/eaaCatalog/repository.html que é um cheirinho do livro Patterns of Enterprise Application Architecture.
O Domain Store é de certa forma uma evolução do DAO quando se afina a interface do DAO e se acrescentam responsabilidades Do DAO ao Domain Store.
Então usando Hibernate a presença dos DAOs é dispensável, correto?
Se eu utilizar métodos add e remove no próprio Repositório, como foi sugerido pelo peerless e utilizar Hibernate, seria necessário mais alguma classe ou padrão entre o Repositório e o banco de dados?
No site do hibernate existe um artigo sobre a utilização do Hibernate com DAOs. Seria só pra centralizar toda a utilização dele num ponto só?
[quote=wagnerfrancisco]Então usando Hibernate a presença dos DAOs é dispensável, correto?
[/quote]
Sim.
Não.
Não. Seria para publicitar o Hibernate. O conceito de Hibernate dentro de um DAO é absurdo. O DAO é supostamente plugável. O Hibernate não é plugável. Logo, inserir uma coisa não plugável dentro de uma plugável é uma asneira.
Imagine que vc tem um DAO para o Banco XTO ficticio que não suporta JDBC e vc teve que criar tudo mão. Vc fez seu sistema e está tudo funcionando. Um dia o hibernate dá suporte a esse banco e vc pensar :" Crio um DAO com o hibernate lá dentro e dico livre para usar qq banco que o hibernate suporta, inclusive o XTO" … beleza, vc faz isso. Eis senão quando vc descobre que a performance do seu sistema caiu abruptamente. Vc investiga o problema e descobre que o hibernate está fazendo eager loading de tudo. Maior @#$@. Vc precisa resolver isso. Vc descobre o padrão “Open view in session” e resolve. Mas agora o seu DAO depende de um filtro de servlet que controla o session… hummm… gambiarra , não ?
Escolher usar hibernate é uma decisão de arquitetura , não de design. Isto porque ele não é completamente encapsulável. Pelo menos ainda não é. Esta é a minha opinião.
sergiotaborda, desculpe-me pela demora da resposta e obrigado por todos os esclarecimentos.
Vou implementar os repositórios com Hibernate e sem utilização dos DAOs. Vou dar uma olhada no Spring também, pra injetar os repositórios. Ainda tenho algumas dúvidas, mas aí acho que foge um pouco do que foi proposto no início do tópico.
Nem li tudo que escreveram aí porque me deu preguiça. hahahaha…
Mas pelo que vi no seu código, sugiro sumir com o ID do repositório. Não faz muito sentido ter ID no repositório, pois pra ele o interessante é o objeto completo.
Fica aí uma dica e se isso já foi mencionado, me desculpem. =)
[quote=feliperod]Mas pelo que vi no seu código, sugiro sumir com o ID do repositório. Não faz muito sentido ter ID no repositório, pois pra ele o interessante é o objeto completo.[/quote] Não é id do repositório, apenas um identificador do tipo de chave primária sobre o bean associado. Geralmente isto é utilizado para um DAO generico, porém pode ser ainda customizado.
Mas é desse ID do bean mesmo que estou dizendo que deve sumir do Repositorio. Lembre-se o repositório é um conceito de negócio e no negócio geralmente não existe ID. O campo ID é um campo estritamente de infraestrutura. Na verdade no negócio uma entity significa um conjunto único de dados. Só adicionamos o ID porque é uma best pratice de banco de dados, mas é meio bad smell ficar trabalhando com ID no meio do Domain Model.
Identificadores existem em todas as entidades do negócio como forma de diferenciar cada uma, logo não entendi qual o seu ponto, você sugere traduzir o termo para algo que pertenca a linguagem do dominio ou abolir identificadores completamente do dominio?
Desculpa a sinceridade mas não ler um tópico e comentar é contribuir para piorar a qualidade do debate.
Muitas vezes identificadores fazem parte do domínio e mesmo que não façam eles vão fazer parte do critério de consulta de alguma forma, já que quando o usuário entra uma url como site.com.br/coisas/123 você tem que buscar por esse ID usando o repositório e criar um objeto para fazer QBE pode até esconder o ID mas acaba criando um problema de semântica (criar um objeto que você está procurando? isso não existe na linguagem do domínio).
Isso não quer dizer que você vai necessariamente ter um buscarPorId no Repositório -apesar que na maioria das vezes vai- porque este pode estar embutido em algum outro critério -formando um Query Object/Specification com semântica maior- mas esconder completamente IDs do domínio quase sempre é inviável.
[quote=pcalcado]-apesar que na maioria das vezes vai- porque este pode estar embutido em algum outro critério -formando um Query Object/Specification com semântica maior[/quote] não entendi quanto a citação pcalcado.
Nossa, ficou cnfuso mesmo. Deixa eu tentar reescrever:
Isso não quer dizer que você vai necessariamente ter um buscarPorId no Repositório (apesar que na maioria das vezes vai) porque esta busca pode estar presente em alguma outra, provavelmente formando um Query Object/Specification que tem semântica maior dentro do domínio que uma busca por id crua e genérica. Esconder completamente IDs do domínio, no entanto, quase sempre é inviável.