Repositório, Dao e sua relação com a Entidade...  XML
Índice dos Fóruns » Java Básico
Autor Mensagem
pcalcado
Moderador
[Avatar]

Membro desde: 08/03/2004 17:19:35
Mensagens: 5174
Localização: Sydney - Australia
Offline

hlegius wrote:Na verdade estou tentando entender a solução que o Repository podem vim a ajudar a resolver. Talvez por não conhecê-la direito eu esteja direcionando de forma errada minhas perguntas/afirmações sobre. Acho que é esse o problema =/ Talvez até não tenha sentido nenhum usar Repository para um objeto Pessoa (como coloquei no exemplo lá no começo), mas realmente estou tentando entender o básico dela: o que é, para que serve como posso aplicá-la.


Sobre estes exemplos espec'ificos leia o Patterns of Enterprise Applications Architecture, de Martin Fowler.

hlegius wrote:
(..)Using Domain-Driven Design the model expressed in software is the model that the business understands.(..)

Talvez seja esse o motivo que esteja recomendando a mim que esqueça os DDD por hora, não ?


Por ai. Usando a terminologia do artigo, DDD eh uma decisao de 3o nivel mas voce ainda esta com dificuldade no segundo nivel, portanto eh melhor se concentrar nele.

hlegius wrote:
Então, estava tentando dizer que o exemplo que você passou seria algo bem simples e sem preocupações com Repository, camada de persistência bem abstraída e etc.; Apenas um "corredor" entre as entidades e a camada de persistência.


Isso.


****o restante deste post nao deveria estar em java basico****

tnaires wrote:
1) O método adicionaUsuario() recebe apenas dois parâmetros. Qual seria a forma ideal de proceder quando há 15, 20 parâmetros ou mais? Um usuário do GUJ me perguntou isso um tempo desses, e eu sugeri a ele duas coisas: utilizar um Map<String, String> com os nomes dos parâmetros e seus conteúdos, ou projetar uma DSL interna.


Dado que quem chama este facade eh a camada de apresentacao nao teria problema (falando de regra geral, depende do dominio) se esta criasse o objeto usuario e passase este para o Service layer. Acho que no seu exemplo voce teria que criar objetos baseados nos parametros (talvez usando uma Factory que pertence a Camada de Negocios) e passar estes objetos para os servicos.

tnaires wrote:
2) Voltando a DDD só um pouquinho ( e sem querer focar exclusivamente nos padrões mas já focando ), ao invés de chamar o DAO eu poderia, por exemplo, injetar o repositório direto nesse Façade aí né? Ou o uso do repositório é exclusivo da camada de negócios?


Este exemplo eh completamente (e propositalmente) nao DDD. Num exemplo DDD voce nao pode ter um conceito de infra-estrutura como DAO sendo usado diretamente por uma classe de negocios. Neste caso -considerando que seu Repositorio seja uma implementado por um DAO JDBC- voce usaria Dependency inversion principle e sim, faria algo injetar o Repositorio.

tnaires wrote:
3) O Façade acima compõe a camada de aplicação certo?


Exato. lembre-se, entretanto, que Camada de Aplicacao geralmente eh diluida entre Apresentacao e Negocios.

tnaires wrote:
Seria ele, conceitualmente falando, o mesmo Service de que Eric Evans trata no livro dele?


Nao. Os Services do Evans possuem granularidade menor, o Service Layer do exemplo acima cuida de todo o fluxo de uma dada operacao.

Eh muito dificil dar um exemplo de Service sem ter um dominio em mente mas vamos pensar no seguinta: suponha que eu estaj num estacionamento de shopping. Quando o cliente entra de carro neste ele inforam em qual loja ir'a. O sistema guia ele para a vaga disponivel mais proxima daquela loja.

Em pseudo-Java:


Note a diferenca entre Estacionamento#indicarvaga() e LocalizadorDeVagas#locaziarDeAcordoCom(). O primeiro 'e um Service Layer , ele executa o fluxo da aplicacao, nao regra de negocio em si. O segundo eh um Service Domain-Driven Design, ele executa regra de negocio.

Phillip Calçado "Shoes"
http://fragmental.tw/
http://blog.fragmental.com.br/
"It is unfortunate that much of what is called 'object-oriented programming today is simply old style programming with fancier constructs." - Alan Kay
[Email] [WWW] [Yahoo!] [MSN]
hlegius
JavaChild
[Avatar]

Membro desde: 07/05/2006 14:29:25
Mensagens: 126
Localização: Guarulhos, SP
Offline

pcalcado wrote:Sobre estes exemplos espec'ificos leia o Patterns of Enterprise Applications Architecture, de Martin Fowler.

Opa, pode deixar ! Assim que eu finalizar os Head-first que tenho aqui irei providenciar uma cópia deste do Fowler (o qual é bem falando pelo fórum ao que pude perceber)

pcalcado wrote:Usando a terminologia do artigo, DDD eh uma decisao de 3o nivel mas voce ainda esta com dificuldade no segundo nivel, portanto eh melhor se concentrar nele.

Certo !

Muito obrigado pelas dicas !

http://programe.me
Zend Certified Engineer
ArchLinux - A simple lightweight Linux Distribution
[WWW] [MSN] [ICQ]
tnaires
GUJ Master
[Avatar]

Membro desde: 22/12/2003 08:05:58
Mensagens: 1678
Localização: Porto Alegre/RS - Natal/RN
Offline

OK Phillip, obrigado pelas respostas. Como sempre, muito esclarecedoras.

Tarso Nunes Aires

Blog - http://cabritin.wordpress.com/
Delicious - http://delicious.com/tnaires
Twitter - @tnaires

sergiotaborda
GUJ Expert
[Avatar]

Membro desde: 22/03/2005 20:57:48
Mensagens: 3433
Offline

hlegius wrote:
O repositório ao que entendi é uma interface dessas DAO's. Ele é único para a entidade (no exemplo Pessoa) e é ele que faz a comunicação com as DAO's existentes MySQLPessoaDAO, XMLPessoaDAO, etc.


Exato. Repare como a herança não está de acordo com o que vc mesmo disse.
1) O repositorio é único para cada entidade. Se existem várias implementações possiveis, então não é único. Logo, o repositorio não pode ser uma interface. Tem que ser um objeto concreto ( não abstrato, não interface, não estático)
2) O repositorio comunica com um ou mais DAO. Primeiro, herança não é comunicar. Comunicar significa uma relação de cooperação (de composição). Segundo, se o DAO for a implementação de repositorio então não tem como chamar mais do que um DAO.

Acho que isto já basta para mostrar que o Repositorio é um objeto distinto do DAO. Quando digo distintio quero dizer que um não RepositoryPessoaherda ou implementa o outro. A relação é Reposiotorio--->(1...*) DAO e não Repositorio---|> DAO nem DAO---|>Repositorio


Só que por exemplo: supondo que o objeto Pessoa ao ser persistido, necessite que: seja persistido o objeto no Database e que salve num XML, por exemplo, a hora em que ele foi persistido. São 2 rotinas: database e XML (exemplo beeem irreal, mas só pra constar mesmo). Neste caso surreal, o Repository iria servir "apenas" como uma façade para o XMLPessoaDao e JDBCPessoaDao ? Ou ele executa outra tarefa ?


Ele atua realmente como um façade para o DAO. Mais geralmente atual como façade para a camada inferior de preservação ( se existir). Repare que o repositorio gravar em dois daos já é uma coisa que justifica o façade (Que é o padrão para agrupar várias chamadas em uma so). Mas ele executa outas tarefas sim.
A tarefa principal de um repositorio é possibilitar que as instancias das entidades se encontrem e que os serviços encontrem as instâncias das entidades. Ou seja, ele é principalmente um "procurador" (locator). Por isso o respositorio tem um monte de métodos find. O ponto é que os métodos recebem os parametros da pesquisa e não a pesquisa em si.
O Repositório tem que criar um pesquisa no formato que o DAO entende (SQL para bancos, XPath para XML etc... )
No seu exemplo, o repositorio encontra as instancias onde ? no XML ou no banco ? ( ja que ele grava nos dois)
Essa decisão é algo que o Repositorio faz. Ele decide isso , cria a pesquisa, envia ao DAO no formato que ele tende e trabalha os dados de retorno. Um DAO tipicamente retorna algo semelhante a um resultSet ou a um Map. O Repositorio tem que instanciar a classe, preencher com os dados, verificar estados, etc... pode injetar objetos "filhos" etc...
Hoje em dia, um DomainStore é preferivel ao DAO extamente porque ele faz esse serviço chato de instanciação, preenchimento, etc.. Ou seja, ele assume o papel e o Repositorio simplesmente delega. Mas o Repositorio ainda tem que criar as pesquisas.
Na real, se usar o Hibernate que é uma implementação de um DomainStore, o Repositorio é onde vc cria os Criteria (ou HQL se quiser...) e envia ao Hibernate.



Veja, explico em código rapidinho:





Estaria essa idéia sobre o Repository correta, ou não tem nada a vê ?


É isso ai mas sem o static. O Repositorio é um objeto concreto. Mas tome atenção que o codigo salva() em pessoa não é necessário para o Repositorio.
Esse codigo em pessoa é o uso de um outro padrão (ActiveRecord). Vc pode salavar a pessoa simplesmente fazendo



Como a ideia é que o Repositorio funciona como uma coleção (ou seja, tem estado) vc não vai criar o respositorio cada vez que precisa dele. A sau solução foi usar static, mas isso viola o primeiro objetivo que é ter um objeto concreto e segundo, cria um "objeto global" que é sempre ruim. A solução é usar outro padrão o Registry. Este sim é um objeto com métodos só estáticos que funciona como um Map global com assinaturas especiais. Por exemplo:



ou simplesmente



Várias variações são possiveis. Por exemplo:



Vc pode argumentar que pode incluir este codigo em pessoa e inverter as coisas (pessoa.salva()). É verdade.
Mas eu não recomendo isso. É que com active record qualquer objeto pode mandar salvar a pessoa, mesmo quando não deveria.
O salvar é uma ação protegida por validações e outros processos do sistema que não cabem dentro do objeto pessoa ou do método salvar. Como conceito é legal, mas na prática é ruim se vc quer um sistema com fácil manutenção.( se vc não quiser, ignore o que eu disse...)



sergiotaborda wrote:O Repositório é um objeto permite aos objetos das entidades encontrarem outros objetos de entidade. Ele são modelados como se fossem coleções de dados com métodos especiais para procurar esses dados.


Nesta sua explicação você diz que o Repositório permite uma entidade encontrar outra a qual tenha relação. Isso seria algo como: a entidade "Inventario" usa o RepositorioProdutos para localizar Produtos com certas especificações e retornar a coleção desses Produtos para ela ?


Exatamente isso.

OU ela usaria o RepositorioInventario e este conectaria-se às interfaces das DAO's dos Produtos para retornar um Produto[*] ?


Definitivamente não.
Poderiamos ligar o RepositorioInventario ao RepositorioProdutos mas nunca ligar o RepositorioInventario ao DAOProdutos.

O repositorio se liga ao seu proprio DAO. Apenas a ele. Se precisar de entidades diferentes ele se liga ao Repositorio da outra entidade , não ao DAO dela. O DAO é visivel apenas pelo seu proprio Repositorio.

Veja que vc pode ter um mecanismo agnostico como o hibernate que tem a mesma invocação qualquer que seja a entidade, e desse ponto de vista o RepositorioInventário vè a mesma interface do Hibernate que o RepositorioProdutos. Mas isso não significa que deve haver quebre de encapsulamento. Isto porque se , por exemplo, o RepositorioCidade usa o RepositorioEstado que usa um EstadoDAOXML se o RepositorioCidade chamar directamente o EstadoDAOXML terei duas chamadas em lugares diferentes. Ao mudar para EstadoDAOJDBC terei que mudar em dois lugares. Mas se o RepositorioCidade chamar sempre o RepositorioEstado e apenas ele chamar o DAO, não terei problemas em mudar em um lugar apenas. Isto é válido mesmo quando o DAO é agnóstico (é o mesmo para qualquer entidade) ou quando se usa um DomainStore (como o Hibernate) que é agnóstico por construção.

Repito : o repositorio tem a responsabilidade de preservar os dados como e onde quiser. Ninguem pode atropelar esta responsabildiade. Outros objetos do sistema apenas podem invocar o repositorio e nunca os objetos que o repositorio usa. Isso seria uma violação grave do encapsulamento tornando o repositório de fato inutil.


Se for isto, a coleção seria "criada" no Repositório e devolvida já montada (num vetor, ou algo do tipo) pronto para o "Inventario", certo ? Assim eu teria que alterar somente o RepositorioProduto em caso de atualização na entidade Produto, penso.


Exatamente

Você entendeu. Agora faça o seu código corresponder às suas palavras. (porque não está... )

Criando sua própria API de Validação



Blog do MiddleHeaven
[WWW]
sergiotaborda
GUJ Expert
[Avatar]

Membro desde: 22/03/2005 20:57:48
Mensagens: 3433
Offline

hlegius wrote:Bom... depois de procurar mais infos, montei a seguinte idéia:

Objeto Pessoa tem injetado via setter um RepositorioImpl
RepositorioImpl <implementa> Repositorio para que tal obedeça o contrato
O repositorioImpl contém as chamadas às Daos Necessárias para fazer a persistência do objeto, ou seja, se para persistir o Objeto Pessoa eu precisar de 2 tabelas distintas + umas configs no XML, eu chamaria 2 ou até 3 implementações de DAO's para que cada uma delas execute sua tarefa própria que seria mapear o objeto para um sistema relacional (database) e uma outra DAO para persistir dados no XML.

Pelo que entendi de repositório seria isto. Ele abstrai diferentes DAO's para que a entidade não saiba o que tem por trás daquele repositório.


Sim. É isso mesmo.
O seu problema é que está pensando que "Cada entidade tem o seu repositorio" significa "Cada instancia da entidade tem uma instancia de um repositorio para a classe propria para a entidade". É isso que é falso.

Imagine um Repositorio assim



Este cara funciona para qualquer entidade E.
Agora pense numa implementação com Hibernate



Esta implementação funciona para qualquer entidade E.

Agora tome atenção no Registro de reposiotorios.



Agora vc pode fazer findALL para qualquer entidade do seu sistema e só teve que criar 3 classes.

Se vc entendeu o padrão Repositorio vc irá perguntar: mas e se a minha entidade tem métodos especiais no repositorio?
O registro é um registro porque coisas podem ser registradas nele ( ). Ou seja, no inicio do sistema vc pode
simplesmente registrar um repositorio especifico para um classe de entidade



Depois pega da mesma forma e faz um cast para usar os métodos especiais ou simplesmente cria um método no registro que faça o cast por si.

Vc vai ter muito poucas classes e por isso um sistema mais conciso com manutenção mais fácil. Nada de 300 DAO

This message was edited 1 time. Last update was at 08/10/2008 09:30:04


Criando sua própria API de Validação



Blog do MiddleHeaven
[WWW]
hlegius
JavaChild
[Avatar]

Membro desde: 07/05/2006 14:29:25
Mensagens: 126
Localização: Guarulhos, SP
Offline

sergiotaborda wrote:Exato. Repare como a herança não está de acordo com o que vc mesmo disse.
1) O repositorio é único para cada entidade. Se existem várias implementações possiveis, então não é único. Logo, o repositorio não pode ser uma interface. Tem que ser um objeto concreto ( não abstrato, não interface, não estático)
2) O repositorio comunica com um ou mais DAO. Primeiro, herança não é comunicar. Comunicar significa uma relação de cooperação (de composição). Segundo, se o DAO for a implementação de repositorio então não tem como chamar mais do que um DAO.

Acho que isto já basta para mostrar que o Repositorio é um objeto distinto do DAO. Quando digo distintio quero dizer que um não RepositoryPessoaherda ou implementa o outro. A relação é Reposiotorio--->(1...*) DAO e não Repositorio---|> DAO nem DAO---|>Repositorio


Bem, agora que você deu essa aula sobre Repository e DAO deixa eu monstrar um pequeno exemplo (agora mais real):

Entidade Pessoa:


Classe "de ação" Inventario



RepositoryInventarioImpl:



RepositoryProdutoImpl:



e a app teste...




Bom. O que acontece é o seguinte:

1. Crio alguns objetos Produtos
2. "Inicializo" o Inventario
3. Adiciono os produtos 1 a 1 no Inventario
4. Chamo o estoque.salva() que irá persistir as informações no Inventario.

Agora vem o principal:
5. No Inventario#salva é chamado o RepositoryInventarioImpl#salvar() que recebe um List com os produtos do Inventario.
6. Esse Repository por sua vez, "delega" a ação de adicionar os produtos para outro Repository (como você sugeriu (explico abaixo o por quê fiz)), o RepositoryProdutoImpl.
7. RepositoryProdutoImpl, recebe esse List e como é tarefa dele, prepara os dados para serem repassados a DAO's necessária - neste caso somente 1 DAO, a JDBCProdutoDao.
8. JDBCProdutoDao se comunica com o database via jdbc e retorna um bool que é transmitido até chegar no Inventario#salvar(), ou, em caso de exceptions, dispara a Exception e essa se propagará até a Inventario#salvar() também.

Legal, agora os motivos disto (na minha opinião e entendimento à sua explicação):

RepositoryInventarioImpl existe, pois talvez eu possa ter alguma rotina de persistência na parte de inventário, logo, eu faço uma façade da RepositoryProdutoImpl para "juntar as rotinas". Façade simples, onde não impede a comunicação direta com o RepositoryProdutoImpl. (como pede o próprio pattern).

sergiotaborda wrote:A tarefa principal de um repositorio é possibilitar que as instancias das entidades se encontrem e que os serviços encontrem as instâncias das entidades. Ou seja, ele é principalmente um "procurador" (locator). Por isso o respositorio tem um monte de métodos find. O ponto é que os métodos recebem os parametros da pesquisa e não a pesquisa em si.


Isso quer dizer que caso eu venha a ter a necessidade de persistir alguma outra informação relacionada à entidade Produtos - como o usuário que fez a alteração no estoque, criando uma espécie de log - durante um ação de salvar(), eu poderia muito bem deixar a cargo do meu RepositoryInventarioImpl receber as novas entidades (via parametros no comportamento) e cuidar de persisti-las para mim, correto ?

sergiotaborda wrote:O Repositório tem que criar um pesquisa no formato que o DAO entende (SQL para bancos, XPath para XML etc... )

Certo. Nada de mau teria caso eu repassasse o objeto Pessoa para a DAO, pois até onde sei, é na DAO que eu crio o Statement, e passo os valores usando bindParam, por exemplo.

sergiotaborda wrote:Um DAO tipicamente retorna algo semelhante a um resultSet ou a um Map. O Repositorio tem que instanciar a classe, preencher com os dados, verificar estados, etc... pode injetar objetos "filhos" etc...

Jóia. DAO retorna o renomado ResultSet para o Repositório responsável, o qual se vira para criar os objetos de retorno.

Então o Repository basicamente garante que o objeto seja "traduzido" para o idioma do banco de dados/XML/TXT, e ao mesmo tempo, "traduz" tabelas e linhas em objetos que o sistema entende. Ele é nosso tradutor, nosso modem (analogia ruim, mas vale).

sergiotaborda wrote:Mas tome atenção que o codigo salva() em pessoa não é necessário para o Repositorio.
Esse codigo em pessoa é o uso de um outro padrão (ActiveRecord).

Verdade. No ActiveRecord a implementação da persistência é feita diretamente na entidade. Já com o Repository aplicado, ele é quem cuida disto.

sergiotaborda wrote:Como a ideia é que o Repositorio funciona como uma coleção (ou seja, tem estado) vc não vai criar o respositorio cada vez que precisa dele. A sau solução foi usar static, mas isso viola o primeiro objetivo que é ter um objeto concreto e segundo, cria um "objeto global" que é sempre ruim. A solução é usar outro padrão o Registry. Este sim é um objeto com métodos só estáticos que funciona como um Map global com assinaturas especiais. Por exemplo:


huum! O Registry é o cara que "evita" que eu fique fazendo instâncias de Repositórios em todos comportamentos de persistência, como eu fiz no exemplo acima:



Ele me auxilia no "encapsulamento" dessas instâncias... seria meio que uma fábrica (factory) então ?

sergiotaborda wrote:É que com active record qualquer objeto pode mandar salvar a pessoa, mesmo quando não deveria.
O salvar é uma ação protegida por validações e outros processos do sistema que não cabem dentro do objeto pessoa ou do método salvar.

Certo. No caso, o Inventario é uma classe que apenas possui comportamentos de persistência, logo, neste caso em especifico, não há problema em trabalharmos com o salvar() nele, correto ?

Falando nisto, veja:



Antes de jogar no List mais um objeto Produto, o Inventario comunica-se com o objeto Produto que foi passado a ele para ter certeza de uma regra em espeficico. Caso, negativo nada é feito, do contrário, o produto entra na lista do Inventario.
A pergunta é: validações de regra de negócio é preferível ficar sempre no modelo, correto ? Pois uma possível implementação seria validar no RepositoryProdutoImpl, mas eu mesmo não achei muitos motivos para isto...


sergiotaborda wrote:Repito : o repositorio tem a responsabilidade de preservar os dados como e onde quiser. Ninguem pode atropelar esta responsabildiade. Outros objetos do sistema apenas podem invocar o repositorio e nunca os objetos que o repositorio usa. Isso seria uma violação grave do encapsulamento tornando o repositório de fato inutil.


Certo. Repare que no exemplo, eu mando um List de Produtos ao repositório para serem persistidos. Repare também que é o Repository quem faz a interação item a item e adiciona usando a DAO em jogo. Logo, no meu exemplo, eu não conseguiria "pular" o Repositório (algo como: Inventario -> ProdutoDAO), pois estou dependendo da interação. Por isto, estaria meu repositório executando tarefas que não é obrigação dele ? Ou seja, essa interação deveria ficar lá no Inventario#salvar(), ou o Repositório pode colocar a mão-na-massa também ?

Realmente você explicou de forma excelente ! Sem dúvidas foi bem útil para mim !


Abraços e muito obrigado ! (y)

http://programe.me
Zend Certified Engineer
ArchLinux - A simple lightweight Linux Distribution
[WWW] [MSN] [ICQ]
sergiotaborda
GUJ Expert
[Avatar]

Membro desde: 22/03/2005 20:57:48
Mensagens: 3433
Offline

hlegius wrote:
Bem, agora que você deu essa aula sobre Repository e DAO deixa eu monstrar um pequeno exemplo (agora mais real):


Classe "de ação" Inventario




Repare como vc mesmo assume que esta classe não é uma entidade. é uma "acção".
Na realidade ela está mais para serviço do que para entidade. (repare que não tem estado, e portanto não tem identidade, logo não é uma entidade).

Isso leva à conclusão que Inventário não é uma entidade e sim um serviço. Como tal, o inventário não tem repostorio.

Só paa deixar claro que o inventário é um serviço chamarei a classe de InventarioService.

Outra pista de que Inventário não é uma entidade é que o repositorio de inventário salva produtos. Então ele é um repositorio de produtos. Então não é um repositorio de inventário. Este paradoxo mostra que tb que inventário não é uma entidade e não precisa de repositorio.

Por outro lado vc está usando Inventário como uma coleção de produtos como se pode ver no main.
Na realidade vc precisa de um objeto ajudante para ser essa coleção e o inventário trabalha com essa coleção

Chamemos este objeto ajudante de ProductBag.
Remova o repositorioinventario e rearranje o inventário assim:









O inventário atua controlando quais produtos do bag podem ser adicionado ou não. Isso é um exemplo conceptual de uma regra
de dominio/negocio.


sergiotaborda wrote:A tarefa principal de um repositorio é possibilitar que as instancias das entidades se encontrem e que os serviços encontrem as instâncias das entidades. Ou seja, ele é principalmente um "procurador" (locator). Por isso o respositorio tem um monte de métodos find. O ponto é que os métodos recebem os parametros da pesquisa e não a pesquisa em si.


Isso quer dizer que caso eu venha a ter a necessidade de persistir alguma outra informação relacionada à entidade Produtos - como o usuário que fez a alteração no estoque, criando uma espécie de log - durante um ação de salvar(), eu poderia muito bem deixar a cargo do meu RepositoryInventarioImpl receber as novas entidades (via parametros no comportamento) e cuidar de persisti-las para mim, correto ?


Poderia, mas seria bem mais facil criar uma outra entidade (auditoriaProduto) o serviço receber o usuário e invocar o repositorio de produto normalmente, e depois o repositorio de AuditoriaProduto com referencia ao produto , usuário, data e resto dos paramentros de auditoria. Estes "cutting concerns" - coias que temos que fazer que não pertencem ao dominio, mas ao sistema - são melhores de tratar em serviços. Aliás , o resto da sua aplicação só deve mexer com serviços quando vai alterar alguma coisa.
É por o que eles fazem tende a alterar-se com o tempo.


sergiotaborda wrote:O Repositório tem que criar um pesquisa no formato que o DAO entende (SQL para bancos, XPath para XML etc... )

Certo. Nada de mau teria caso eu repassasse o objeto Pessoa para a DAO, pois até onde sei, é na DAO que eu crio o Statement, e passo os valores usando bindParam, por exemplo.


Não teria nada de mal em principio. Ao passar o objeto ara o DAO e o DAO passar o objeto de volta, isso significa que o DAO está acoplado ao objeto. Isso provavelmente significa que cada entidade tem o seu proprio DAO. Isso funciona, é possivel de usar assim, é sobretudo util quando usa bancos legados. É um trade-off possivel em certas circustancias. Mas se vc está fazendo um sistema do zero, onde pode criar seu proprio modelo de dominio e de dados, o DAO não têm por quê ser acoplado. É melhor usar um DomainStore como o JPA ou o Hibernate ( ou fazer o seu próprio) .
Portanto, o "mal" e o "bem" dependem das cisrcunstancias. Das escolhas que vc tem que fazer, dos constrangimentos com que tem que lidar ( tempo, pessoal, tecnológico , legado, etc... )

Conceptualmente não tem nenhum problema a sua escolha... desde que seja tomada com consciência.


sergiotaborda wrote:Um DAO tipicamente retorna algo semelhante a um resultSet ou a um Map. O Repositorio tem que instanciar a classe, preencher com os dados, verificar estados, etc... pode injetar objetos "filhos" etc...

Jóia. DAO retorna o renomado ResultSet para o Repositório responsável, o qual se vira para criar os objetos de retorno.

Então o Repository basicamente garante que o objeto seja "traduzido" para o idioma do banco de dados/XML/TXT, e ao mesmo tempo, "traduz" tabelas e linhas em objetos que o sistema entende. Ele é nosso tradutor, nosso modem (analogia ruim, mas vale).


a realidade o modem é a camada de persistencia (DAO, ou DomainStore). Mas dependendo da implementação da camada de persistencia tlbv o repositorio tenha que fazer algumas tarefas como as que falei. O ideal é que ele não tenha que as fazer ( dai a importancia do DomainStore), mas caso sejam necessárias a responsabilidade é do repositorio. Básicamente, quando mais inteligente a sua camada de persistencia, menos trabalho o repositorio faz.


sergiotaborda wrote:Como a ideia é que o Repositorio funciona como uma coleção (ou seja, tem estado) vc não vai criar o respositorio cada vez que precisa dele. A sau solução foi usar static, mas isso viola o primeiro objetivo que é ter um objeto concreto e segundo, cria um "objeto global" que é sempre ruim. A solução é usar outro padrão o Registry. Este sim é um objeto com métodos só estáticos que funciona como um Map global com assinaturas especiais. Por exemplo:


huum! O Registry é o cara que "evita" que eu fique fazendo instâncias de Repositórios em todos comportamentos de persistência, como eu fiz no exemplo acima: (...)

Ele me auxilia no "encapsulamento" dessas instâncias... seria meio que uma fábrica (factory) então ?


Não. Fabrica é fábrica e registro é registro. Registro é tipo um livro. Vc escreve (normalmente uma vez) e depois le (várias vezes). Fabrica é um objeto que cria o objeto. O Registro pode usar uma fábrica e ser um pouco inteligente, contudo, são dois padrões diferentes. Note que no exemplo do HibernateRepository eu digo que poderia usar um Factory em vez de dar o new directamente. Fabricas são substitudos de "new". Registros são substitutos de Maps globais e variáveis static.

Mas sim, com o registro vc evita ter que saber qual é o repositorio certo. Vc configura isso no inicio do sistema ( ou deixa o registro se virar sozinho fazendo algumas convenções) e depois só chama pelos repositorios - sem saber a verdadeira implementação deles ! (encapsulamento : essa é a vantagem)

Outro detalhe final. Vc ainda faz seus repositorios implementarem um interface. Entenda que a interface e a implemnetação estão fortemente acopladas. tão fortemente que nunca existirão duas classes implementando a mesma interface. Logo, a interface é ínutil. Vc pode herdar de um repositorio genérico (padrão Layer Supertype) , mas não separar interface e implementação. O repositorio tem que ser concreto ! já vimos que não faz sentido não ser concreto. Lembre-se disso. Vai poupar muita codificação desnecessária.

This message was edited 1 time. Last update was at 09/10/2008 08:19:05


Criando sua própria API de Validação



Blog do MiddleHeaven
[WWW]
hlegius
JavaChild
[Avatar]

Membro desde: 07/05/2006 14:29:25
Mensagens: 126
Localização: Guarulhos, SP
Offline

sergiotaborda wrote:Repare como vc mesmo assume que esta classe não é uma entidade. é uma "acção".
Na realidade ela está mais para serviço do que para entidade. (repare que não tem estado, e portanto não tem identidade, logo não é uma entidade).


aaah sim! Repository só aplica-se as entidades do sistema. Camadas de serviços não possui Repository ou DAO pois elas apenas executam ações para alguma entidade.
Aproveitando, deixa eu lhe perguntar: neste caso tudo bem, pois o Repository numa ação de findAll() por exemplo, retornaria uma coleção de Produto[*] para o Inventário. Mas vamos supor uma situação em que não haja uma classe de serviço para atrelar à entidade. Eu acho que ficaria estranho um objeto Pessoa receber de RepositoryPessoa uma coleção de Pessoa[*], não acha ? Como eu poderia proceder nestes casos ?

sergiotaborda wrote:Por outro lado vc está usando Inventário como uma coleção de produtos como se pode ver no main.
Na realidade vc precisa de um objeto ajudante para ser essa coleção e o inventário trabalha com essa coleção

Chamemos este objeto ajudante de ProductBag.


Com isso você sugere que nas classes de serviço eu não deva "manipular" as entidades da forma como eu fiz (criando uma coleção de Produtos) ? Elas (classe de serviço) devem sempre executar as ações e repassar o resultado, nada além disso ?


sergiotaborda wrote:Poderia, mas seria bem mais facil criar uma outra entidade (auditoriaProduto) o serviço receber o usuário e invocar o repositorio de produto normalmente, e depois o repositorio de AuditoriaProduto com referencia ao produto , usuário, data e resto dos paramentros de auditoria.


Vejamos: neste caso teriamos uma nova entidade (AuditoriaProduto), o RepositórioAuditoriaProduto e estes seriam manipulados pela camada de serviço Inventario igualmente o produto, penso. Neste caso, o serviçoInventario iria persistir o objeto no sistema e na sequência iria fazer a auditoria usando o RepositorioAuditoriaProduto.

Algo como:
Inventario#salva() --> RepositorioProduto -> Dao -> database
Inventario#salva() --> RepositorioAuditoriaProduto -> Dao(da auditoria) -> XML file

Como neste exemplo a Auditoria é uma regra para toda persistência do Produto, poderia eu deixar a implementação da entidade AuditoriaProduto a cargo da entidade Produto, não ? Funcionaria meio que uma composição. Produto morre, auditoria morre também. Parece-me lógico, o que acha ?

segiotaborda wrote:a realidade o modem é a camada de persistencia (DAO, ou DomainStore). Mas dependendo da implementação da camada de persistencia tlbv o repositorio tenha que fazer algumas tarefas como as que falei. O ideal é que ele não tenha que as fazer ( dai a importancia do DomainStore), mas caso sejam necessárias a responsabilidade é do repositorio. Básicamente, quando mais inteligente a sua camada de persistencia, menos trabalho o repositorio faz.


Certo. Entendi !

sergiotaborda wrote:Outro detalhe final. Vc ainda faz seus repositorios implementarem um interface. Entenda que a interface e a implemnetação estão fortemente acopladas. tão fortemente que nunca existirão duas classes implementando a mesma interface. Logo, a interface é ínutil. Vc pode herdar de um repositorio genérico (padrão Layer Supertype) , mas não separar interface e implementação. O repositorio tem que ser concreto ! já vimos que não faz sentido não ser concreto. Lembre-se disso. Vai poupar muita codificação desnecessária.


Pois é. Estava reparando isso enquanto montava os testes aqui. Nesses casos a interface(interface mesmo) de nada serve/ajuda no Repositório. Obrigado pelo toque !


Abraço!

http://programe.me
Zend Certified Engineer
ArchLinux - A simple lightweight Linux Distribution
[WWW] [MSN] [ICQ]
Eduardo Amuri
What is classpath?

Membro desde: 26/01/2009 23:01:37
Mensagens: 6
Offline

A discussão estava interessante...
 
Índice dos Fóruns » Java Básico
Ir para:   
Powered by JForum 2.1.8 © JForum Team