Factory para persistir classe adequadas ou existe outra partner para isso

[quote=YvGa][quote=fabiocsi]Sérgio,

No seu exemplo acima, nao estou vendo muita diferença entre seu Repository e um DAO.

Se eu falei besteira, poderia me explicar a diferença?[/quote]

Corrijam-me se eu estiver errado, mas a diferenca de um DAO e um Repository eh a finalidade de cada um. Eles podem ser implementados exatamente da mesma maneira, mas o intuito eh diferente.
[/quote]

Não. O intuito é diferente e a implementação é diferente. Não faz sentido criar uma factory de repositorios pelo simples motivo que a lógica contida neles é a logica do negocio. Se as lógicas mudam, os repositórios mudam, não se criam outros.
Enquanto nos DAO a logica é sempre a mesma, é invariante, a implementação é diferente conforme a API real
Ou seja um XMLDAO e um JDBCDAO têm a mesma interface e procuram os mesmos dados , apenas os procuram em lugares distintos e com API distintas. É neste sentido que digo que a logica é invariante.
A logica dos Repositorios pode mudar conforme a lógica do negocio, ou porque contém logica que tem que se modificada ou porque as entidades com que eles trabalham foram modificadas.

DAO é uma coisa plugável. Atrás de um DAOFactory todos os DAO são iguais.
Repositorio não é plugável, ele faz parte do coração da aplicação.

Reaproveitar logica de negocios não é simples, e normalmente não se faz. Logo cada sistema terá seus repositorios proprios.

Voltando ao assunto:
Chegamos a 3 modelagens eu acho, sendo assim em uma tentativa modesta vou tentar apontar os pros e contras de cada um … alias quando eu tiver um tempo vou abrir um tópico somente para discussão do assunto: ?Cliente Pessoa uma modelagem mal vista? e lá sim vou colocar os pros e contras.
Aqui vou somente perguntar.

Tb concordo q com certeza não existe interface comum entre pessoa e empresa, seria muito forçado abstrair esses dois. Logo PessoaFisica e PessoaJurica são conceitos fiscais(inclusive de cada pais). Por chamo as classes de empresa e pessoa.
Desculpe estar sendo redundante ou especificando detalhes que parecem ridículo, mas como eu já disse estou apavorado com o que aparece de modelagens sem nexo na internet. Acho q por isso POO tem um efeito contrario quando usado por determinadas empresas.
Bom vamos lá.

Na imagem A temos a modelagem que eu escolhi. Fora as questões que o Sergio já resolveu, inclusive com muita propriedade, fico em duvida: Optando pela modelagem A posso criar um método na minha interface Cliente chamado Tp_P_E : Integer;
Assim quando implementado por ClienteEmpresa ou ClientePessoa ele retorna ?0? quando o Cliente for herdado de Empresa e ?1? quando herdado de Pessoa. Logo quando eu estiver manipulando a interface Cliente saberei por exemplo chamar a pela de cadastro de ClientePessoa ou ClienteEmpresa. Aqui temos o inverso do que estávamos tratando antes. A questão é, esse método Tp_P_E é uma injambração ou é valido. A esse método seria publico.
A quanto ao mapeamento, no BD, usando a Opção A, Tenho uma Tabela Pessoa e outra ClientePessoa. ClientePessoa tem o mesmo ID que Pessoa assim estabeleço a relação. O Sergio comentou em fazer uma única Tabela Cliente, porem se Pessoa é uma Classe que pode persistir não ficaria mais fácil pensando no bd ter uma tabela Pessoa e ClientePessoa. Ou tb poderia ter tabela Pessoa somente para a classe pessoa, e Cliente para as classes ClientePessoa e CLienteEmpresa e para interface Cliente tb.

A quanto a modelagem C q seria algo parecido com a que o YvGa porem fiquei em duvida como implementar um interface para o tipo (Empresa ou Pessoa) vai usar. Se alguém já usou e tiver algum comentário por favor fique a vontade.


[quote=Joaquimnabuco]Voltando ao assunto:
Chegamos a 3 modelagens eu acho, sendo assim em uma tentativa modesta vou tentar apontar os pros e contras de cada um … alias quando eu tiver um tempo vou abrir um tópico somente para discussão do assunto: ?Cliente Pessoa uma modelagem mal vista? e lá sim vou colocar os pros e contras.
Aqui vou somente perguntar.
[/quote]

O dificil de responder é que não existe ‘A’ solução , sempre existe "UMA’ solução. Qual é a solução para o modelo de “pessoa” para um ERP é diferente da de “pessoa” para uma agenda.

Em traços gerais clientes são capacidades das pessoas A pessoa é cliente ou não é independnete de ser cliente.
Aliás o conceito de prospect é o de uma pessoa que ainda não é cliente mas é interessante à empresa. Concerteza não foi ter um cadastro complexo de prospect, o mais será o nome e contacto como numa agenda. Mas após a primeira venda essa mesma pessoa é agora um cliente. É como se “cliente” fosse um estado de "pessoa"
Pessoas podem ser prospects , clientes , ex-clientes. Podem, simultameamente ser fornecedores , vendedores, empregados, etc… Seja qual for o(s) papel(eis) que a pessoa representa para o sistema, os dados cadastrais da pessoas são os mesmos.

Tem que saber , para começar , o objetivo do modelo, pois não ha um modelo bom para todas as situações.
Quer dizer, eu acho que ha, só que não será simples. A complexidade de tal modelo pode ser importante num ERP por exemplo que tem que lidar com vários aspectos da empresa, mas numa agenda é overkill.

[quote=sergiotaborda][quote=YvGa][quote=fabiocsi]Sérgio,

No seu exemplo acima, nao estou vendo muita diferença entre seu Repository e um DAO.

Se eu falei besteira, poderia me explicar a diferença?[/quote]

Corrijam-me se eu estiver errado, mas a diferenca de um DAO e um Repository eh a finalidade de cada um. Eles podem ser implementados exatamente da mesma maneira, mas o intuito eh diferente.
[/quote]

Não. O intuito é diferente e a implementação é diferente. Não faz sentido criar uma factory de repositorios pelo simples motivo que a lógica contida neles é a logica do negocio. Se as lógicas mudam, os repositórios mudam, não se criam outros.
Enquanto nos DAO a logica é sempre a mesma, é invariante, a implementação é diferente conforme a API real
Ou seja um XMLDAO e um JDBCDAO têm a mesma interface e procuram os mesmos dados , apenas os procuram em lugares distintos e com API distintas. É neste sentido que digo que a logica é invariante.
A logica dos Repositorios pode mudar conforme a lógica do negocio, ou porque contém logica que tem que se modificada ou porque as entidades com que eles trabalham foram modificadas.

DAO é uma coisa plugável. Atrás de um DAOFactory todos os DAO são iguais.
Repositorio não é plugável, ele faz parte do coração da aplicação.

Reaproveitar logica de negocios não é simples, e normalmente não se faz. Logo cada sistema terá seus repositorios proprios. [/quote]

Acho q exagerei ao dizer “exatamente da mesma maneira”, mas ficou uma duvida especificamente qto a forma q estou utilizando.

Realmente nao os implemento da mesma maneira, meus Repositorios nao tem factory, nem sao abstratos, e como vc disse, mudam se algo mudar nas regras de negocio.

O q eu faco eh fazer com q os repositorios instanciem e executem metodos nos DAOs, portanto eles tem metodos com mesmo nome e assinatura q eu tenho nos DAOs, por exemplo, o repositorio.salvarCliente(cliente), em sua implementacao salva o cliente atraves de um metodo salvarCliente no DAO. Ha algo nisso tudo q eu estou perdendo?

[quote=YvGa]
O q eu faco eh fazer com q os repositorios instanciem e executem metodos nos DAOs, portanto eles tem metodos com mesmo nome e assinatura q eu tenho nos DAOs, por exemplo, o repositorio.salvarCliente(cliente), em sua implementacao salva o cliente atraves de um metodo salvarCliente no DAO. Ha algo nisso tudo q eu estou perdendo?[/quote]

No método salvar do repositorio ( que deveria ter um nome menos ligado a persistência e mais ligado a operações de conjuntos) realmente não ha muito a fazer do que delegar para o DAO. A menos, é claro, que exista um trigger qualquer no momento da inserção ou modificação da entidade no repositorio. Nos casos simples a delegação resolve.
Contudo, a necessidade de existir um Repositorio vem do uso de aggregados, ou seja, grafos de vários objetos cujos estado é interligado. Ao persistir a raiz do grafo têm que ser tb persistidas as folhas. Ou não. A logica vai depender do que é o grafo e como o aggregado é montado. É esta tradução complexa que exige o uso de Repositorio.

Sem essa complexidade, não ha necessidade de um repositório que apenas delegue para o DAO. Bom, isso é que dizem. Eu acho que mesmo assim vale a pena ter um repositório genérico que faça essas operações básicas de delegação. Isto porque um dia mais tarde elas podem deixar de ser simples e a delegação insuficiente.

Vc tem então duas opções. 1) só usar repositorio quando existe uma complexidade inerente às entidades e suas classes relacionadas. 2) não usar repositorio quando tudo o que ele faz é delegar para o DAO.

Mas , entenda-se que na opção 2 estaremos pulando uma camada e isso poderá ser prejudicial. Fora que, ao usar um misto, poderá complicar a manutenção/evolução do sistema.

Sérgio:

Então se eu tenho um objeto Pessoa, e esse objeto possui um List de objetos Endereco…
Eu teria um PessoaDAO, um EnderecoDAO, e o meu PessoaRepository teria por exemplo um
método getById que chamaria os DAOS e me devolveria o objeto Pessoa com seus enderecos?

[quote=fabiocsi]Sérgio:

Então se eu tenho um objeto Pessoa, e esse objeto possui um List de objetos Endereco…
Eu teria um PessoaDAO, um EnderecoDAO, e o meu PessoaRepository teria por exemplo um
método getById que chamaria os DAOS e me devolveria o objeto Pessoa com seus enderecos?[/quote]

Pelo q eu entendo eh isso mesmo.

A unica coisa eh q eu nao uso um EnderecoDAO, por endereco ser Value Object (pelo menos no meu dominio) entao, o PessoaDAO eh quem vai ser responsavel por persistir e recuperar a lista de enderecos.

[quote="fabiocsi "] Então se eu tenho um objeto Pessoa, e esse objeto possui um List de objetos Endereco…
Eu teria um PessoaDAO, um EnderecoDAO, e o meu PessoaRepository teria por exemplo um
método getById que chamaria os DAOS e me devolveria o objeto Pessoa com seus enderecos?
[/quote]

Acho que o YvGa repondeu a essa questão. Se , se , Endereço é em objeto de valor (Value Object) que pertence ao grafo ( Aggregation) de Pessoa, então é o repositório de Pessoa que deve procurar os endereços da pessoas e adicioná-los ao objeto pessoa.
Se , se, Endereço é tb uma entidade ele precisa do seu repositorio.

Então PessoaDAO é na realidade o seu PessoaRepository. Que sistema de persistencia vc usa no PessoaDAO ?

Tb concordo com o Sérgio.

Seu PessoaDAO ta fazendo a funcao do PessoaRepository.

Bom, pelo que tenho aprendido nesse topico, nem PessoaDAO nem EnderecoDAO devem envolver objetos de domínio.

RepositorioPessoa delega para a interface PessoaDAO q persiste o objeto Pessoa e seus List. Eu uso na implementacao de PessoaDAO hibernate.

Entao me diga o que seus Repositorios fazem, ALÉM de delegar.

[quote=fabiocsi]Tb concordo com o Sérgio.

Seu PessoaDAO ta fazendo a funcao do PessoaRepository.
[/quote]

Na verdade nao. Apenas tenho os dois. O Repositorio delega a acao ao DAO.

[quote]
Bom, pelo que tenho aprendido nesse topico, nem PessoaDAO nem EnderecoDAO devem envolver objetos de domínio.[/quote]

Talvez eu esteja errado, mas nao vejo problema nisso. Acho q o problema esta qdo os objetos de dominio conhecem os DAOs.

Se eu implementasse a sua interface DAO para PessoaDAO usando JDBC puro, seu sistema funcionaria ?
Como a minha implementação saberia que é responsável por recuperar/guardar tb os endereços ?
A resposta é: se souber existe uma violação de camadas, porque está sendo deixada logica referente ao dominio (no caso a dependencia que pessoa tem de endereço) dentro do DAO, que não pertence ao dominio.

Ora, se eu não posso substituir o DAO por causa desse problema, então não ha porquê ter um DAO. Faça essa logica diretamente no repositorio. não ?

Vou citar o q o Sergio disse aqui sobre isso.

Nao tinha visto essa diferenca sutil. Como eu uso hibernate, um session.save no DAO resolve o problema e eu nao preciso me preocupar com a forma q os enderecos serao gravados.

Se nao fosse o hibernate realmente concordo com vc q nao funcionariae o codigo sim deveria ser implementado no respositorio. A pergunta eh: eu sempre tenho q tratar disso no repositorio, mesmo q (como no caso do hibernate) eu nao precise, apenas pela possibilidade de um dia precisar? E se eu quisesse implantar com jdbc estaria errado em tbm delegar essa tarefa ao DAO? Mas se nao, como eu implementaria de diversas formas, diversas tecnologias? Nao seria util esconder essa implementacao ate do repositorio?

Agora ficou a duvida.

O hibernate é um hibrido. Ele não é apenas um DAO, ele é tb um manager. No caso do Hibernate não faz sentido usar DAO, apenas Repository que delega para o Hibernate diretamente.
Mas isso é ruim se eu quiser mudar meu mecanismo de persistência ! - dirá vc.

Pois é. O problema é que se vc usa hibernate vc ja está amarrado a um mecanismo.
Foi o exemplo que dei, se mudar a implementação da interface para JDBC puro não vai funcionar porque o JBDC puro não tem metadados de relacionamento, não controla se o objeto está “dirty” etc… , ou seja, não é um manager. Na prática ao usar hibernate o sistema está livre para usar qq banco, mas não para usar qq sistema de persistência. Se o objetivo é sempre usar Banco de Dados, usar o hibernate não é um problema. Só é problema no caso generico de poder mudar o DAO para qualquer sistema de persistência.

Se o meu sistema tem que funcionar em qualquer mecanismo de persistência, então o repositório não pode assumir que o DAO fará o trabalho X ou Y e tem que tratar o DAO como um burro de carga entre a persistencia e a memória.
Se o seu sistema funciona apenas com Banco de Dados Relacionais suportados pelo Hibernate , use o hibernate dentro do repositorio directamente. Isso implica que o repositorio pode tirar partido das capacidades especiais do hibernate, e neste caso não faz sentido usar o padrão DAO.

[quote=sergiotaborda]
Se o meu sistema tem que funcionar em qualquer mecanismo de persistência, então o repositório não pode assumir que o DAO fará o trabalho X ou Y e tem que tratar o DAO como um burro de carga entre a persistencia e a memória.
Se o seu sistema funciona apenas com Banco de Dados Relacionais suportados pelo Hibernate , use o hibernate dentro do repositorio directamente. Isso implica que o repositorio pode tirar partido das capacidades especiais do hibernate, e neste caso não faz sentido usar o padrão DAO. [/quote]

Eu ou dar mais uma olhada na definicao de repositorio e depois tornamos a discussao. Mas a principio eu discordo pois acho q os detalhes de como os objetos sao persistidos e carregados podem ser responsabilidade dos DAOs.

E se eu quiser usar outro db (db4o por exemplo, q ando testando) eu tenho q reescreer todos os meus repositorios? Ou pior, usar meus repositorios com factories e interfaces, transformando-os erdadeiramente em DAOs.

[quote=YvGa][quote=sergiotaborda]
Se o meu sistema tem que funcionar em qualquer mecanismo de persistência, então o repositório não pode assumir que o DAO fará o trabalho X ou Y e tem que tratar o DAO como um burro de carga entre a persistencia e a memória.
Se o seu sistema funciona apenas com Banco de Dados Relacionais suportados pelo Hibernate , use o hibernate dentro do repositorio directamente. Isso implica que o repositorio pode tirar partido das capacidades especiais do hibernate, e neste caso não faz sentido usar o padrão DAO. [/quote]

Eu ou dar mais uma olhada na definicao de repositorio e depois tornamos a discussao. Mas a principio eu discordo pois acho q os detalhes de como os objetos sao persistidos e carregados podem ser responsabilidade dos DAOs.

E se eu quiser usar outro db (db4o por exemplo, q ando testando) eu tenho q reescreer todos os meus repositorios? Ou pior, usar meus repositorios com factories e interfaces, transformando-os erdadeiramente em DAOs.
[/quote]
Não. Esse é exatamente o ponto. VC vai escrever apenas outro DAO, o repositório é mesmo sempre. Por isso que o DAO não pode conter logica de dominio , de forma que possa ser substituido. Mas o repositorio pode e deve ter essa logica.

A dependencia que existe entre uma classe e outra é um conhecimento de dominio e não de persistencia. O nome da tabela, arquivo , url , sei lá … onde os objetos de dominio sem guardados é conhecimento do mecanismo de persistencia e não do dominio.
Os detalhes da carga são da responsabilidade do DAO, mas o relacionamento entre as classes/entidade não é um detalhe da carga.

[quote=fabiocsi]Sérgio:

Então se eu tenho um objeto Pessoa, e esse objeto possui um List de objetos Endereco…
Eu teria um PessoaDAO, um EnderecoDAO, e o meu PessoaRepository teria por exemplo um
método getById que chamaria os DAOS e me devolveria o objeto Pessoa com seus enderecos?[/quote]

Certo, Sergio. Mas esse eh o ponto onde comeca a discussao. Nesse caso, o PessoaDAO nao pode ser o responsavel pela reconstrucao do objeto Pessoa? Nada de errado em o Repositorio ter essa funcao, mas nao ficaria melhor no DAO (a nao ser, obviamente, q eu nao queira recuperar a lista de endereco na hora da construcao do objeto Pessoa).

Eu vejo o padrao DAO como a ponte entre um objeto concreto e sua persistencia, e nesse caminho q ele se “desintegra” e vai para o mundo relacional. E na volta se reintegra para o mundo dos objetos. O responsavel por isso seria o DAO e nao repositorio, certo?

Tudo muda qdo eu nao quero recuperar a lista de enderecos no instante da criacao do objeto, nesse caso, sim o repositorio eh quem tem a responsabilidade de recompor, aos poucos, o objeto.

Não. Se o DAO tem como missão traduzir os seus objetos de negocio para a persistencia e vice-versa ele seria um tradutor. Todo o tradutor precisa conhecer as duas linguas envolvidas. Significa portanto que o DAO conheceria sua linguagem de negocio ( o seu dominio). Ora, vc não deve querer isso.
Se o DAO conhece o dominio, vc não pode plugar outro DAO.

Imagine assim:
Vc tem a aplicação A e a B. A é uma aplicação financeira e seu dominio são contas , transções, saldos etc. B é uma aplicação de vendas e seu dominio são produtos, itens, pedidos, orçamentos, etc…

Obviamente as lógicas de dominio são diferentes. Elas são encapsuladas em repositorios além de nas respectivas entidades e demais objetos do dominio.

Agora imagine que vc tem um SQLServer e vc cria um DAO para ele. Ambos, A e B serão persistidos no SQLServer (em bancos diferentes, claro). O DAO é o mesmo. Tanto para A como para B.
Este é o objetivo do DAO, ser substituivel e reutilizável.

Agora pense que alguem resolve matar o SQLServer e subtituir por PostgreSQL. Vc não muda a sua aplicação, vc apenas muda o DAO. Que continua sendo o mesmo para A e B.
Repare que o codigo dos repositórios não mudou , nem o das entidades.

Agora pense que alguem quer fazer um demo da aplicação A. O demo deverá correr sobre HSQL embarcado.
Vc cria um terceiro DAO para HSQL. Não ha mudança nenhum das regras de negocio. Apenas das interfaces de persistência.

Para que este troca-troca dos DAO seja possível, eles devem ignorar ao máximo os objetos de dominio.
Assim os DAO são apenas burros de carga. Se eles são burros , onde fica a inteligência do dominio ? Nos repositorios. Essa inteligencia, essa logica, é igual , quer a pesistencia seja SQLServer,HSQL, Potgress ou até memso XML , Prevayler, DB4O , etc … É até a mesma se o DAO for volátil ( ou seja, que não persiste verdadeiramente)