Repository & DAO

Olá Pessoal,

Apesar de ser assunto velho aqui no GUJ, gostaria de demonstrar a forma como utilizo repositories e DAO’s e saber o que acham.
Os repositories trato-os como pertencentes à camada de negocios e os DAO’s como uma camada de infra-estrutura de acesso à dados, com os todos os metodos de CRUD necessarios. Quanto aos repositorios, nos momentos em que preciso realizar alguma operacao de consulta, adicao, edicao, remocao a partir de uma entidade da camada de negocios, crio uma interface representando o repositorio e declaro o metodo do qual necessito (ex: obterMovFinanceirasAPartirDe(Date data)) na entidade de negocio. Por fim, faco o DAO que impleneta operacoes de CRUD da entidade de negocio implementar a interface repository que defini antes, desta forma, de dentro da camada de negocios eu apenas me referencio a repositories, mas obtenho na verdade, DAO’s.

É assim que eu faço tb.
O objetivo de um Repository é justamente isolar a lógica de negócios da lógica de persistência. As suas classes de negócio sempre se comunicam com a interface do repositório e ignoram que objeto está cumprindo esse papel, se é um DAO acessando Postgre ou um leitor de arquivos XML.

[quote=joparibeiro]Olá Pessoal,

Apesar de ser assunto velho aqui no GUJ, gostaria de demonstrar a forma como utilizo repositories e DAO’s e saber o que acham.
Os repositories trato-os como pertencentes à camada de negocios e os DAO’s como uma camada de infra-estrutura de acesso à dados, com os todos os metodos de CRUD necessarios. Quanto aos repositorios, nos momentos em que preciso realizar alguma operacao de consulta, adicao, edicao, remocao a partir de uma entidade da camada de negocios, crio uma interface representando o repositorio e declaro o metodo do qual necessito (ex: obterMovFinanceirasAPartirDe(Date data)) na entidade de negocio. Por fim, faco o DAO que impleneta operacoes de CRUD da entidade de negocio implementar a interface repository que defini antes, desta forma, de dentro da camada de negocios eu apenas me referencio a repositories, mas obtenho na verdade, DAO’s.[/quote]

você estava indo bem até que disse que faz o DAO implementar a interface do repository. Isto é um erro.
Veja que vc mesmo falou que o reposiorio está na camada de negeocios e o DAO na infra. Ou seja, o DAO está abaixo do repositorio.
Pela regra básica da separação de camadas, camadas de baixo não podem implementar/usar coisas da camada de cima. Logo, se o seu dao importa a interfacedo Repositorio na camada de cima, está errado.

A relação entre o DAO e o Repositorio não é de herança é de composição. O repositorio TEM-UM dao. O repositorio não É um dao.

Por outro lado se vc fizer dos jeito que está fazendo ( e vamos ignorar a questão da inversão de camadas aqui) o repositorio não faz absolutamente nada. Ou melhor, não pode fazer absolutamente nada. Ele vira um Decorador/Proxy do DAO este não é o objetivo do repositório.

O objetivo do repositorio é : na camada de negocio, estabelecer as regras de pesquisa das instancias de uma entidade.
O repositorio não serve para fazer CRUD, apenas o R ( retrive) , o resto vc pode usar um Service que chama o DAO. O service é transacional ( ele cria uma transação) o repositorio apenas participa de uma transação.
É claro, que vc pode estender o repositorio para ter o resto do CRUD, mas esse não é a sua essência.

Dito isto, o repositorio deve ter métodos como vc exemplificou bem tal como obterMovFinanceirasAPartirDe(Date data). Como isso é feito ?
É feito estabelecendo um critério de busca. O papel do repositorio é estabelece este critério. Que entidades tenho que pesquisar e com que relações é o que o repositório responde.
E a parte real , concreta de executar o critério de busca e realmente buscar as coisas ? Isso é o papel do DAO.

Agora veja bem : Se a o critério de busca mudar vc altera o repositorio. Se a forma de executar a busca mudar , vc altera o dao. Isto demonstra que as responsabilidades estão bem separadas.
No seu design, se o critério mudar vc altera o DAO e se a forma de busca mudar, vc altera o DAO. Má separação de responsabilidade.

Agora imagine que tem dois tipos de DAO, o Dao para SQL e o DAO para MongoDB. A sua regra de negocio mudou alguma coisa ? Não. Ela está definida no repositorio e ele não mudou porque acrescentei uma nova implementação do DAO.
Isto também demonstra que o DAO tem que ser composto no repositorio, pois só assim eu posso usar o mesmo repositorio( a mesma regra de negocio) com bancos de dados diferentes. Se houver uma questão de herança, simplesmente não consigo isto e mais, tenho que implementar o cirtério de pesquisa outra vez . No seu design se vc quiser incluir o mongoDB vc tem que incluir nele a logica de negocio. Isto nega o principio DRY e portanto não é um bom design.

O repositório serve única e exclusivamente para agrupar queries de pesquisa. São essas queris que são a regra de negocio. A execução da regra não é uma regra de negocio, é uma regra de infra ( por isso o dao é da camada de infra).

Dito isto, o repositório não se define com uma interface. Se define com uma classe. Porquê ? Porque a regra de negócio é única. Se vc mudar a regra, vc está mudando o negocio. Portanto vc só precisa de uma implementação.
O repositorio não segue o padrão Service ( uma interface + N implementações) como os serviços de dominio ou os daos. O repositorio é ele mesmo um padrão diferente. Se formos comparar o repositório está mais para uma filho de Specification Object ou Query Object Factory do que Service.

P.S( não falei nada sobre domainstore para não confundir. vamos ficar apenas na dicotomia Repositorio - Dao por enquanto)

1 curtida

[quote=sergiotaborda][quote=joparibeiro]Olá Pessoal,

Apesar de ser assunto velho aqui no GUJ, gostaria de demonstrar a forma como utilizo repositories e DAO’s e saber o que acham.
Os repositories trato-os como pertencentes à camada de negocios e os DAO’s como uma camada de infra-estrutura de acesso à dados, com os todos os metodos de CRUD necessarios. Quanto aos repositorios, nos momentos em que preciso realizar alguma operacao de consulta, adicao, edicao, remocao a partir de uma entidade da camada de negocios, crio uma interface representando o repositorio e declaro o metodo do qual necessito (ex: obterMovFinanceirasAPartirDe(Date data)) na entidade de negocio. Por fim, faco o DAO que impleneta operacoes de CRUD da entidade de negocio implementar a interface repository que defini antes, desta forma, de dentro da camada de negocios eu apenas me referencio a repositories, mas obtenho na verdade, DAO’s.[/quote]

você estava indo bem até que disse que faz o DAO implementar a interface do repository. Isto é um erro.
Veja que vc mesmo falou que o reposiorio está na camada de negeocios e o DAO na infra. Ou seja, o DAO está abaixo do repositorio.
Pela regra básica da separação de camadas, camadas de baixo não podem implementar/usar coisas da camada de cima. Logo, se o seu dao importa a interfacedo Repositorio na camada de cima, está errado.

A relação entre o DAO e o Repositorio não é de herança é de composição. O repositorio TEM-UM dao. O repositorio não É um dao.

Por outro lado se vc fizer dos jeito que está fazendo ( e vamos ignorar a questão da inversão de camadas aqui) o repositorio não faz absolutamente nada. Ou melhor, não pode fazer absolutamente nada. Ele vira um Decorador/Proxy do DAO este não é o objetivo do repositório.

O objetivo do repositorio é : na camada de negocio, estabelecer as regras de pesquisa das instancias de uma entidade.
O repositorio não serve para fazer CRUD, apenas o R ( retrive) , o resto vc pode usar um Service que chama o DAO. O service é transacional ( ele cria uma transação) o repositorio apenas participa de uma transação.
É claro, que vc pode estender o repositorio para ter o resto do CRUD, mas esse não é a sua essência.

Dito isto, o repositorio deve ter métodos como vc exemplificou bem tal como obterMovFinanceirasAPartirDe(Date data). Como isso é feito ?
É feito estabelecendo um critério de busca. O papel do repositorio é estabelece este critério. Que entidades tenho que pesquisar e com que relações é o que o repositório responde.
E a parte real , concreta de executar o critério de busca e realmente buscar as coisas ? Isso é o papel do DAO.

Agora veja bem : Se a o critério de busca mudar vc altera o repositorio. Se a forma de executar a busca mudar , vc altera o dao. Isto demonstra que as responsabilidades estão bem separadas.
No seu design, se o critério mudar vc altera o DAO e se a forma de busca mudar, vc altera o DAO. Má separação de responsabilidade.

Agora imagine que tem dois tipos de DAO, o Dao para SQL e o DAO para MongoDB. A sua regra de negocio mudou alguma coisa ? Não. Ela está definida no repositorio e ele não mudou porque acrescentei uma nova implementação do DAO.
Isto também demonstra que o DAO tem que ser composto no repositorio, pois só assim eu posso usar o mesmo repositorio( a mesma regra de negocio) com bancos de dados diferentes. Se houver uma questão de herança, simplesmente não consigo isto e mais, tenho que implementar o cirtério de pesquisa outra vez . No seu design se vc quiser incluir o mongoDB vc tem que incluir nele a logica de negocio. Isto nega o principio DRY e portanto não é um bom design.

O repositório serve única e exclusivamente para agrupar queries de pesquisa. São essas queris que são a regra de negocio. A execução da regra não é uma regra de negocio, é uma regra de infra ( por isso o dao é da camada de infra).

Dito isto, o repositório não se define com uma interface. Se define com uma classe. Porquê ? Porque a regra de negócio é única. Se vc mudar a regra, vc está mudando o negocio. Portanto vc só precisa de uma implementação.
O repositorio não segue o padrão Service ( uma interface + N implementações) como os serviços de dominio ou os daos. O repositorio é ele mesmo um padrão diferente. Se formos comparar o repositório está mais para uma filho de Specification Object ou Query Object Factory do que Service.

P.S( não falei nada sobre domainstore para não confundir. vamos ficar apenas na dicotomia Repositorio - Dao por enquanto)[/quote]

Tem um exemplo literal disto? Tanto do repositório, quanto do DAO?

[quote=sergiotaborda][quote=joparibeiro]Olá Pessoal,

Apesar de ser assunto velho aqui no GUJ, gostaria de demonstrar a forma como utilizo repositories e DAO’s e saber o que acham.
Os repositories trato-os como pertencentes à camada de negocios e os DAO’s como uma camada de infra-estrutura de acesso à dados, com os todos os metodos de CRUD necessarios. Quanto aos repositorios, nos momentos em que preciso realizar alguma operacao de consulta, adicao, edicao, remocao a partir de uma entidade da camada de negocios, crio uma interface representando o repositorio e declaro o metodo do qual necessito (ex: obterMovFinanceirasAPartirDe(Date data)) na entidade de negocio. Por fim, faco o DAO que impleneta operacoes de CRUD da entidade de negocio implementar a interface repository que defini antes, desta forma, de dentro da camada de negocios eu apenas me referencio a repositories, mas obtenho na verdade, DAO’s.[/quote]

você estava indo bem até que disse que faz o DAO implementar a interface do repository. Isto é um erro.
Veja que vc mesmo falou que o reposiorio está na camada de negeocios e o DAO na infra. Ou seja, o DAO está abaixo do repositorio.
Pela regra básica da separação de camadas, camadas de baixo não podem implementar/usar coisas da camada de cima. Logo, se o seu dao importa a interfacedo Repositorio na camada de cima, está errado.

A relação entre o DAO e o Repositorio não é de herança é de composição. O repositorio TEM-UM dao. O repositorio não É um dao.

Por outro lado se vc fizer dos jeito que está fazendo ( e vamos ignorar a questão da inversão de camadas aqui) o repositorio não faz absolutamente nada. Ou melhor, não pode fazer absolutamente nada. Ele vira um Decorador/Proxy do DAO este não é o objetivo do repositório.

O objetivo do repositorio é : na camada de negocio, estabelecer as regras de pesquisa das instancias de uma entidade.
O repositorio não serve para fazer CRUD, apenas o R ( retrive) , o resto vc pode usar um Service que chama o DAO. O service é transacional ( ele cria uma transação) o repositorio apenas participa de uma transação.
É claro, que vc pode estender o repositorio para ter o resto do CRUD, mas esse não é a sua essência.

Dito isto, o repositorio deve ter métodos como vc exemplificou bem tal como obterMovFinanceirasAPartirDe(Date data). Como isso é feito ?
É feito estabelecendo um critério de busca. O papel do repositorio é estabelece este critério. Que entidades tenho que pesquisar e com que relações é o que o repositório responde.
E a parte real , concreta de executar o critério de busca e realmente buscar as coisas ? Isso é o papel do DAO.

Agora veja bem : Se a o critério de busca mudar vc altera o repositorio. Se a forma de executar a busca mudar , vc altera o dao. Isto demonstra que as responsabilidades estão bem separadas.
No seu design, se o critério mudar vc altera o DAO e se a forma de busca mudar, vc altera o DAO. Má separação de responsabilidade.

Agora imagine que tem dois tipos de DAO, o Dao para SQL e o DAO para MongoDB. A sua regra de negocio mudou alguma coisa ? Não. Ela está definida no repositorio e ele não mudou porque acrescentei uma nova implementação do DAO.
Isto também demonstra que o DAO tem que ser composto no repositorio, pois só assim eu posso usar o mesmo repositorio( a mesma regra de negocio) com bancos de dados diferentes. Se houver uma questão de herança, simplesmente não consigo isto e mais, tenho que implementar o cirtério de pesquisa outra vez . No seu design se vc quiser incluir o mongoDB vc tem que incluir nele a logica de negocio. Isto nega o principio DRY e portanto não é um bom design.

O repositório serve única e exclusivamente para agrupar queries de pesquisa. São essas queris que são a regra de negocio. A execução da regra não é uma regra de negocio, é uma regra de infra ( por isso o dao é da camada de infra).

Dito isto, o repositório não se define com uma interface. Se define com uma classe. Porquê ? Porque a regra de negócio é única. Se vc mudar a regra, vc está mudando o negocio. Portanto vc só precisa de uma implementação.
O repositorio não segue o padrão Service ( uma interface + N implementações) como os serviços de dominio ou os daos. O repositorio é ele mesmo um padrão diferente. Se formos comparar o repositório está mais para uma filho de Specification Object ou Query Object Factory do que Service.

P.S( não falei nada sobre domainstore para não confundir. vamos ficar apenas na dicotomia Repositorio - Dao por enquanto)[/quote]

gostei da explicação… incrementou

[quote=drsmachado]
Tem um exemplo literal disto? Tanto do repositório, quanto do DAO?[/quote]

eu não uso com dao, uso com domainstore, mas assim de cabeça seria mais ou menos assim


public class MovRepository {

     private MovDAO dao;

     public MovRepository (MovDAO  dao) {
            this.dao = dao;
      } 

     public List<Movimento> obterMovimentosAPartirDe(Date data){
       
             Criteria<Movimento> criteria = new Criteria<Movimento>()

             criteria.add(new FieldCriterion("dataCriacao" , Operador.MAIOR_QUE , data)); 

             return  dao.execute(criteria); 

   }
    
}

public JDBCMovDao implements MovDAO {

           public List<Movimento> execute(Criteria<Movimento> criteria){

                        // aqui teriamos que fazer o tradicionar abre conexão , fecha, try/catch etc.. 

                      String sql = convertCrtieriaToSQL(criteria);

                     ResultSet set =  con.prepareStatement(sql).executeQuery(); // tou citando de memoria , faz tempo que não mexo com jdbc

                    return convertSetTolist(set , Movimento.class); // usa um reflection para criar as instancias e preencher dos campos do resultset
          }
        
}

Se quiser um MongDBDAO, um XMLDAO ou até o famigerado HibernateDAO é só usar e passar no construtor do repositorio ( usando spring ou cdi ou sei lá… )

O ponto é que a query fica separada da execução. Se mais tarde o cara falar “Putz, a regra agora é só listas as movimentações que não são estornos” ele altera o repositorio e muda a query para

              Criteria<Movimento> criteria = new Criteria<Movimento>()

             criteria.add(new FieldCriterion("dataCriacao" , Operador.MAIOR_QUE , data)); 
             criteria.add(new FieldCriterion("isEstorno" , Operador.EQUALS , false)); 

mais nada. A implementação do DAO é sempre a mesma.
Ha mas agora o cara mudou a versão do mongoDB ( tou inventando aqui) e precisa usar uma outra API para comunicar com o MongoDB - altera só o DAO (e/ou cria outro DAO para a nova api)

Assim também vc tem uma camada de infra que é realmente de infra , ou seja, que vc pode usar em outros sistemas.

[quote=sergiotaborda][quote=drsmachado]
Tem um exemplo literal disto? Tanto do repositório, quanto do DAO?[/quote]

eu não uso com dao, uso com domainstore, mas assim de cabeça seria mais ou menos assim


public class MovRepository {

     private MovDAO dao;

     public MovRepository (MovDAO  dao) {
            this.dao = dao;
      } 

     public List<Movimento> obterMovimentosAPartirDe(Date data){
       
             Criteria<Movimento> criteria = new Criteria<Movimento>()

             criteria.add(new FieldCriterion("dataCriacao" , Operador.MAIOR_QUE , data)); 

             return  dao.execute(criteria); 

   }
    
}

public JDBCMovDao implements MovDAO {

           public List<Movimento> execute(Criteria<Movimento> criteria){

                        // aqui teriamos que fazer o tradicionar abre conexão , fecha, try/catch etc.. 

                      String sql = convertCrtieriaToSQL(criteria);

                     ResultSet set =  con.prepareStatement(sql).executeQuery(); // tou citando de memoria , faz tempo que não mexo com jdbc

                    return convertSetTolist(set , Movimento.class); // usa um reflection para criar as instancias e preencher dos campos do resultset
          }
        
}

Se quiser um MongDBDAO, um XMLDAO ou até o famigerado HibernateDAO é só usar e passar no construtor do repositorio ( usando spring ou cdi ou sei lá… )

O ponto é que a query fica separada da execução. Se mais tarde o cara falar “Putz, a regra agora é só listas as movimentações que não são estornos” ele altera o repositorio e muda a query para

              Criteria<Movimento> criteria = new Criteria<Movimento>()

             criteria.add(new FieldCriterion("dataCriacao" , Operador.MAIOR_QUE , data)); 
             criteria.add(new FieldCriterion("isEstorno" , Operador.EQUALS , false)); 

mais nada. A implementação do DAO é sempre a mesma.
Ha mas agora o cara mudou a versão do mongoDB ( tou inventando aqui) e precisa usar uma outra API para comunicar com o MongoDB - altera só o DAO (e/ou cria outro DAO para a nova api)

Assim também vc tem uma camada de infra que é realmente de infra , ou seja, que vc pode usar em outros sistemas. [/quote]

Interessante! Não conheco domainstore, procurarei conhecer. Em suma, costumo fazer assim:

public class Conta {

	MovimentacoesFinanceiras repository;
	
	public BigDecimal calcularSaldoDesde(Date data) {
		BigDecimal saldo = BigDecimal.ZERO;
		
		// [...]		
		List<MovimentacaoFinanceira> movs = repository.obterMovFinanceirasAPartirDe(data); 						
		// [...]
		
		return saldo;
	}

	public void setRepository(MovimentacoesFinanceiras repository) {
		this.repository = repository;
	}		
}



public interface MovimentacoesFinanceiras {

	public List<MovimentacaoFinanceira> obterMovFinanceirasAPartirDe(Date data);
	
}



public class MovimentacaoFinanceira {
	//[...]
}



public class MovimentacaoFinanceiraDAO implements MovimentacoesFinanceiras {

	@Override
	public List<MovimentacaoFinanceira> obterMovFinanceirasAPartirDe(Date data) {
		//[...]
	}
	
}

Não sei o que seria esta classe conta (uma entidade ?). Se sim, suponho que vc está tentando fazer um active record da vida. Então o método deveria receber a conta como parâmetro.
Além disso repositório deveria fazer o calculo inteiro. Assim :


public BigDecimal saldoDesde(Date data) { // o nome é importante do ponto de vista do chamador isto já é um calculo pela nomenclatura que é usada, colocar a palavra "calcula" é redundante )
		return repository.obterSaldoNaData( this, data); 						
}

Assim vc ganha a possibilidade de poder otimizar no repositório de forma a fazer a soma sem usar a lista ( no futuro vc pode usar fork/join para calcular mais depressa e necesário, ou usar o DAO para usar um SUM no banco em vez de iterar, etc… )
No pior caso , o repositorio vai chamar o outro método , obter a lista , e somar. Mas pelo menos vc tem um lugar só que precisa ser alterado quando a regra mudar. Lembre-se que o repositorio é public e outros objetos pode estar chamando os métodos.
Por exemplo um serviço de report que mostra os saldos de todas as contas.

Note que não apenas impelementar o jpa é repetir todas as queries de novo. Se vc tiver um jpaDAO que faz a soma do saldo e um jdbcDAO que faz a soma do saldo vc está repetindo a definição da querie. Isto é errado ( principio DRY).
A prova que é errado é que se a querie mudar ( pro exemplo, movimentos com estado = X não são somados) vc vai ter que alterar nas duas implementações. Se vc tiver N implemenações vc precisa mudar N vezes.
Além disso a sua camada de infra - suas proprias palavras - contém definição de regra ( entenda que a query é uma regra de negocio). Isto é violação de camadas e violação do SRP ( Single Responsability Principle) que diz que uma classe deve ter uma e uma só responsabilidade. O seu hibrido mutante de repositorio com dao tem duas responsabilidade.

[quote]
Muito obrigado sergiotaborda pelas sugestoes.
Estou estudando seu post sobre DomainStore (http://sergiotaborda.wordpress.com/desenvolvimento-de-software/java/do-dao-ao-domain-store/).[/quote]

veja tambem http://www.javabuilding.com/architecture/arquitetura-com-domainstore-repositorio-e-query-object.html

Não entendi a pergunta. Como o findByName, etc viola o DRY ?
( Vc precisa ler o artigo inteiro, porque aquele exemplo é se um dos sabores do DAO, que é o sabor clássico DAO-Legado. Hoje em dia ninguem mais faz isso. Eu acho até que nunca ninguém fez. Acima estavamos usando o DAO do ultimo exemplo do artigo que usa metadados)

[quote=joparibeiro][quote=sergiotaborda][quote=joparibeiro]
Certo, mas entao o que dizer dos tradicionais DAOs com metodos como findByName, findById, assim como os do exemplo do post http://www.javabuilding.com/academy/patterns/dao.html eles tambem violam o principio de DRY? Sao “hibridos mutantes” de DAO (infra estrutura) e regra de negocio?
[/quote]

Não entendi a pergunta. Como o findByName, etc viola o DRY ?
( Vc precisa ler o artigo inteiro, porque aquele exemplo é se um dos sabores do DAO, que é o sabor clássico DAO-Legado. Hoje em dia ninguem mais faz isso. Eu acho até que nunca ninguém fez. Acima estavamos usando o DAO do ultimo exemplo do artigo que usa metadados)[/quote]

Ora pombas!
Quando voce diz:

A meu entender, esta dizendo que ter metodos como findByName, findById, etc (queries) em uma DAO tornam elas “hibridos mutantes” de DAO (infra estrutura) e regra de negocio, pois queries sao regras de negocio dentro de infra-estrutura (DAO).[/quote]

Mas aqui vc está falando de outra coisa. É importante isso. (É por isso que eu nao uso repo com dao e sim com domainstore)

O dao original quando foi criado era para integrar com legado , chamar procedures, views ,etc… e encapsulava a chamada ao JDBC. Mas ele continha regras de negocios sim. Mas também é preciso entender que nesse tempo a camada de dominio não existia 9 ou era tão fina que era irrelevante). A tela comunicava com o Dao quase que diretamente. O dao clássico sim contêm regras. E a ideia é implementar as mesmas regras uma e outra vez para cada tecnologia que for precisa.
Mas isso não é prático. Exatamente porque é uma violação do SRP. Ai veio o conceito de DomainStore para resolver este problema. Porque se enxergou que a separação tecnologia deveria se desacoplar da separação de negocio. Ou seja, o DAO como isolador de tecnologia era mais util que o DAO clássico ( Dao de legado). Seria interessante mudar do DAO do JDBC para Werbserices, JNI, LDAP, o diabo on demand,mas não implementar a mesma logica de novo.
Ai veio o Hibernate. E ferrou tudo.
As pessoas começaram a pensar que agora o DAO poderia ser implementado usando o hibernate e não mais o JDBC. Ou seja, que o hibernate era uma tecnologia de persistencia equivalente ao jdbc. Não é. O Hibernate é uma implementação do padrão DomainStore, assim como o JPA com o seu EntityManager. No meio disto, nasceu o conceito de ORM. Se eu tivesse ORM, seria tudo mais fácil e o meu DAO não precisaria mais conter as regras e eu poderia usar Criteria como o Hibernate usa. isto levou ao DAO como Mapeador OR. Este ultimo sabor de DAO é o que o pessoa usa hoje, mas é inutil se vc tem acesso ao JPA ou Hibernate. Mas se vc não tem (porque a politica do cliente não permite usar hibernate e vc ainda está no JEE 2 ) é uma solução melhor que o DAO clássico.

entenda que ha uma evolução do conceito do DAO e por isso eu falo no artigo de vários sabores. O DAO classico continha regras. Era tudo em um, como o seu. Ele era feito para comunicar com o legado no tempo que as regras de persistencia estavam no banco com storeprocedure e o diabo (ainda ha instituições que não permitem dar insert e update diretamente na tabela ). Isso era legal para legados, mas e quando o sistema era novo ? O pessoa aprendeu que deve ter DAO, então toca de botar o DAO lá, com a desculpa que isolava a tecnologia de persistencia. Ok, era a mesma coisa que o clássico, mas sem usar procedures. Rápidamente o pessoa entendeu que poderia fazer um AbstractDAO porque a lógica, o SQL e quase tudo era sempre a mesma coisa. E se tivesse metadados era ainda melhor O iBatis meio que segue esta linha.

Hoje o uso direto de dao na sua arquitetura é completamente desnecessário. Se ele existir é um objeto “package protected” da sua camada de persistencia. O padrão a seguir hoje é o DomainStore.
Mas o DomainStore tem o problema inverso do DAO. Ele não admite regras especificas, logo precisamos colocá-las em algum lugar : o repositorio.

Em suma, sim, no DAO classico vc tem violação do DRY e do SRP e por isso que e o DAO evoluiu para o DomainStore (como tento explicar no artigo que vc citou). É natural.

Mas mesmo assim , todos estes anos depois as pessoas insistem em usar DAO, criar um monte de classes desnecessárias que todas herdam de um Abstract que faz tudo sozinho ( se não ha delegação real, portanto não ha hierarquia real) . Pior, criam toda essa estrutura louca para no fim chamar o Hibernate ou o EntityManager. Este design não é bom OO pelos padrões de hoje. Funciona, claro. Mas é muito mais trabalhoso do que deveria e não é flexivel de verdade. Se quiser usar Mongo ou Haddop ou qq outra coisa NoSQL , esquece, o seu abstract não vai funcionar e vc vai ter que implementar uma outra familia de DAOs ( não é por acaso que o Spring Data existe. Ele cobre exactamente este cenário. A ideia deles é que vc define apenas o Repositorio e o Spring cuida do resto com as deridas chamadas para o SQL ou noSQL. O problema é que eles também confundem Repositorio com DAO, mas tecnologicamente é um avanço, por o próximo passo é vc perceber que consegue criar as criterias do repositorio com base no nome do método Esta estratégia, se não me engano veio do RubyOnRails)

[quote=joparibeiro]sergiotaborda, obrigado pelas sugestões mas elas não me convenceram.
Prefiro seguir os conceitos daqui http://blog.fragmental.com.br/2007/03/01/voce-pergunta-001-daos-e-repositorios/ e daqui http://blog.caelum.com.br/possibilidades-de-design-no-uso-do-seu-generic-dao/ pelo menos por enquanto.[/quote]

Eu não estou tentando convencê-lo. Você pode fazer do jeito que quiser. Afinal todos os caminhos vão dar a Roma. O ponto não é esse. O ponto é se isso é um bom design ou não.
Você é livre de usar um mau design. Putz! tem aos montes por ai, e se vc usar um mau design é mais um no coro. O meu objetivo é explicar porque isso é um mau design para o caso que quem estiver lendo esteja procurando fazer diferente de você e usar um bom design.

Primeiro temos a violação da separação de camadas. Se o DAO na camada de integração implementa uma interface da camada de domínio que está acima dela, isso é errado. Se vc criasse um serviço na camada de dominio e o implementasse na camada de integração estaria errado, então porque fazer isso com o dao não é errado ? Está sendo violado o principio de separação de camadas ( que é uma instancia do principio de separação de responsabilidade), então não pode estar certo.

Segundo, o padrão DAO é partido em 1 interface e N implementações para cada entidade. A interface XDAO define o dao de X. A implementação apenas implementa essa interface. Agora, Se a impleemntação tb herda de XRepositorio qual é o papel da interface XDAO ? Nenhum. Apenas é a repetição dos mesmos métodos. Isto está errado porque viola o principio DRY (Don’t Repeat Yourself). Porque eu vou definir uma nova interface que é igual à anterior ? Só para poder usar o nome DAO ? Isso é um sintoma do Sindrome de DAO.

Terceiro, a definição do Repositorio não usa interfaces. Se trata de um objeto apenas. Cito

"it can be worthwhile to build another layer of abstraction over the mapping layer where query construction code is concentrated. "

grifo meu. O Fowler está claramente dizendo que o Repositorio está em outra camada acima da camada de mapeamento. Ou seja, o Repositório não é responsável pelo mapeamento, um outro objeto é , e o repositório delega para esse objeto. O Fowler chama esse padrão e Data Mapper. O DomainStore é um DataMaper e o DAO ( na sua verão ORM “moderna”) também.

Aliás no seu primeiro link podemos ler exactamente isso : “Um DAO (Data Access Object) é uma encarnação do padrão Data Mapper cuja responsabilidade é mapear um objeto para tabelas e vice-versa.”

O erro está na frase “Desta forma o DAO pode se tornar a implementação do Repositório.” Não. O próprio criador do padrão explicou que não é assim. Que o repositório está acima do Data Mapper (DAO). Isto significa que ha uma relação de composição e não de herança, como aliás se pode ver do uml na página do Fowler.

Resumindo: O Repositório não é um DAO. Nem o DAO é um Repositório. Se assim fosse seriam a mesma coisa e seria idiota chamar dois nomes ao mesmo padrão.

O DAO está morto (1) (2), (3), (4) (5). Não é para usar mais. Vamos, por favor, esquecê-lo.

O padrão DAO obriga a numero muito grande de interfaces e classes que acabam não sendo necessários porque tudo se resume a JDBC da mesma maneira. É por isso que as pessoas chegaram no GenericDAO. Porque é uma forma de diminuir as interfaces e o código de implementação. Mas isso não é uma camada DAO de verdade porque só funciona para banco de dados e se uma das entidades não usar o banco esse design volta ao que é o clássico. Isto é sabido e dito pelas próprias pessoas do hibernate. O repositório lhe dá exatamente uma classe por entidade. Simples e eficiente. Vc pluga o domainstore (que é 1 classe para todas as entidades) e pronto.

Acho que as pessoas esquecem que o Repositorio é um elemento da camada de dominio e está associado a um design orientado ao dominio. O DomainStore também. O DAO não.
Orientar ao dominio não é fazer active record e fluent interface. Isso são maneirismos que podem ou não ser uteis dependendo da arquitetura. Orientar ao dominio é fazer a camada de dominio ser independente das outras , poder evoluir sozinha e ser reaproveitada pois é ali que estão as regras de negocio que dão tanto trabalho extrair do cliente. As outras camadas são só tecnologia.

Como disse, não estou tentando convencê-lo. Estou só mostrado que esse é mau design e que usar maus design é contra-producente. Vc é livre de acreditar no que você quiser, mas quem estiver preocupado com os detalhes aqui fica.

sergiotaborda, muito interessante os seus posts. Eu li os links que você mencionou e dei uma olhada bem superficial no projeto MiddleHeaven, muito bom! :smiley:

Eu vi que no MiddleHeaven você criou as interfaces Criteria, DomainStore, etc. Ao usar o Hibernate, por exemplo, teríamos que converter a Criteria do MiddleHeaven para uma Criteria (ou hql) do Hibernate, correto?

Já existe alguma classe que faz esta conversão de maneira genérica? Ou está nos planos do MiddleHeaven este tipo de suporte? Criar classes auxiliares para tecnologias específicas.

Qual sua opinião sobre utilizar diretamente a interface Criteria do Hibernate no projeto? Eu entendo que ficaríamos meio dependentes do hibernate, mas no caso de precisarmos adicionar suporte a outro domain store, bastaria traduzir a criteria do hibernate para ele.

Vou olhar com mais calma o projeto depois.

[quote=wagnerfrancisco]sergiotaborda, muito interessante os seus posts. Eu li os links que você mencionou e dei uma olhada bem superficial no projeto MiddleHeaven, muito bom! :smiley:

Eu vi que no MiddleHeaven você criou as interfaces Criteria, DomainStore, etc. Ao usar o Hibernate, por exemplo, teríamos que converter a Criteria do MiddleHeaven para uma Criteria (ou hql) do Hibernate, correto?
[/quote]

sim.

Existe um plano de implementar o domainstore com o hibernate por baixo dos panos (bypassando a api de dataset que tem agora, que por agora é a única forma de executar contra db).
Usar o hibernate ainda está em estudo. A ideia é prover uma toolbox (jar) à parte com a implementação que usa o hibernate e depois o programador configura para usar.

A resposta tem duas opções. Na primeira vc poderia considerar que poderia criar a sua casca de domainstore como eu exemplifico no worshop do javabuilding. Ai vc teria sua própria API de criteria que seria convertida por baixo dos panos para a api do hibernate.
A segunda é ser prático e usar o hibernate diretamente pois ele já um DomaiStore. Acho que o ideal é usar o hibenate diretamente e só migrar para o seu proprio domainstore quando precisar disso (quando quiser isolar o hibernate por alguma razão. )

Eu pessoalmente prefiro uma camada de indireção (O middleheaven pode ser visto como um conjunto de camadas deste tipo) porque ajuda a esconder algumas nuances do hibernante que não são parte do uso corrente. Mais ou menos como se usa no DAO genérico, tem código que simplesmente é burocrático e uma camada a mais pode ajudar a escondê-lo. Usar o hibernate diretamente funciona perfeitamente, o problema é a portabilidade. Quer mudar para o JPA ? não dá. Outra coisas é poder ser mocado mais facilmente se vc tem uma interface para o domainstore.

Por outro lado do ponto de vista do design fazer o repositorio ou qq outra coisa diretamente dependente do hibernate não é legal.
Uma outra vantagem de fazer sua propria api de criteria e seu próprio domainstore é que pode driblar as regras muito mais facilmente se existir o uso de coisas como procedures ou NoSQL. escondendo por de trás da camada do domainstore onde realmente é feita a pesquisa. Isso pode ser conseguido com criterios especiais como ProcedureDelegationCriteria (tou inventando, não existe este cirterio, mas vc poderia criar se precisasse) e o padrão Strategy dentro do seu domain store.

[quote=sergiotaborda][quote]
Já existe alguma classe que faz esta conversão de maneira genérica? Ou está nos planos do MiddleHeaven este tipo de suporte? Criar classes auxiliares para tecnologias específicas.
[/quote]

Existe um plano de implementar o domainstore com o hibernate por baixo dos panos (bypassando a api de dataset que tem agora, que por agora é a única forma de executar contra db).
Usar o hibernate ainda está em estudo. A ideia é prover uma toolbox (jar) à parte com a implementação que usa o hibernate e depois o programador configura para usar.
[/quote]

Legal.

Certo… o que eu tinha pensado inicialmente era que, se eu estivesse usando a API de Criteria do Hibernate e posteriormente precisasse migrar para um domain store baseado em JPA, eu poderia simplesmente traduzir a criteria do hibernate para o jpa. Mas pensando um pouco ficaria muito estranho, acho que sua ideia é melhor: usar a API do Hibernate inicialmente (para ser prático) e, quando precisar, refatorar e usar uma API própria.

Estou surpreso, perplexo e maravilhado. O que eu li agora foi realmente algo muito embasado, no qual eu nem havia parado para pensar. Fica aqui meus cumprimentos.

Aprendi trocentas coisas:

  • que estava usando DAO de uma maneira mecânica
  • que essa forma “consagrada” viola princípios FUNDAMENTAIS
  • que tenho que investir mais em livros em INGLÊS, porque em praticamente TUDO que se lê por aí em português, temos DAO’s que simplesmente criam os Criterias e delegam o trabalho pesado para o framework de ORM. Bem, isto seria na verdade um repositório sendo chamado de DAO, não seria? Claro, um repositório meio acoplado (acoplado e meio) com a infraestrutura do framework, e nada coeso (pois assume também as tarefas de incluir/atualizar/excluir), mas que por dentro a única coisa que faz é definir critérios de pesquisa (o resto delega para o ORM).

Cito este post: http://blog.aspercom.com.br/2009/08/11/repositorios-ddd/

É outro blog que gosto muito de ler. Queria saber a opinião do Sérgio sobre o que o cara diz ali. Para mim parece que se encaixa. Será?

[quote=MarkKnopfler]Estou surpreso, perplexo e maravilhado. O que eu li agora foi realmente algo muito embasado, no qual eu nem havia parado para pensar. Fica aqui meus cumprimentos.

Aprendi trocentas coisas:

  • que estava usando DAO de uma maneira mecânica
  • que essa forma “consagrada” viola princípios FUNDAMENTAIS
  • que tenho que investir mais em livros em INGLÊS, porque em praticamente TUDO que se lê por aí em português, temos DAO’s que simplesmente criam os Criterias e delegam o trabalho pesado para o framework de ORM. Bem, isto seria na verdade um repositório sendo chamado de DAO, não seria? Claro, um repositório meio acoplado (acoplado e meio) com a infraestrutura do framework, e nada coeso (pois assume também as tarefas de incluir/atualizar/excluir), mas que por dentro a única coisa que faz é definir critérios de pesquisa (o resto delega para o ORM).

Cito este post: http://blog.aspercom.com.br/2009/08/11/repositorios-ddd/

É outro blog que gosto muito de ler. Queria saber a opinião do Sérgio sobre o que o cara diz ali. Para mim parece que se encaixa. Será?[/quote]

1.A mania de usar interfaces

Ora, imaginemos que o repositorio não é uma interfaces. É apenas uma classe normal implementada normalmente. O que ela teria ?


public class RepositorioProduto {

       private QueryInterpreter interpreter;

         public Repositorio  (QueryInterpreter interpreter){
                this.interpreter = interpreter;
     }

    public List<Produto> findDisponiveis(){

            QueryObject query = new QueryObject(); 
               query.add(new FieldCriteria("disponivel", Operator.Equals, true);

               return interpreter.execute(query);

   }
      

}

Dois componentes vitais do repositorio são o QueryObject (mais conhecido como Criteria, mas o nome do padrão é QueryObject) e o Interpeter que é um padrão associado ao queryObject que realmente executa a pesquisa.

O trabalho do repositório é apenas construir estes QueryObject. O exemplo que coloquei ali é trivial, mas a pesquisa pode ser arbitrariamente complexa.
Para injetar dependências se usa o construtor ou métodos set. A interface é irrelevante para este processo de injeção. A testabilidade é obviamente simples pois a necessidade de mock é nula.
Se ha algo a mocar é o interpretador não o repositório.

Porque o repositório precisaria de várias implementações ? Apenas se vc tiver dois ou mais conjuntos de regras para fazer as pesquisas. Mas isto faz sentido ? É como dizer que existem duas formas de pesquisar produtos disponíveis. Não faz sentido.
Mesmo que haja a necessidade de mudar a query porque o modelo mudou ou o negocio mudou Essa alteração é imediata e se reflete imediatamente no sistema. Não existe essa de “vamos fazer a regra hoje e amanhã não”.

O problema, como sempre, é que se confunde a implementação do repositorio com a implementação do DAO mesmo quando se diz que o repositorio e o dao são conceptualmente diferentes. Se são conceptualmente diferentes porque raios têm o mesmo tipo de implementação. Se vc for ver no livro do Eric Evans em nenhum momento o repositorio aparece como interface+implementação. Na realidade é ao contrário. Ele sempre aparece como uma classe concreta que tem uma dependência de uma interface ( que é o interpreter, mas o fowler chama de strategy e outros chamam de datamapper)

  1. Os nomes

A ideia de ter um repositorio de PedidosFaturados e ou outro de TodosOsPedidos é correta pois o Repositorio além de ser um objeto do dominio, ele é associado a Agregados. Agregados são entidades especiais que agregam em si muita informação na forma de composição (agregação) com outras entidades. Isto serve para provar que o repositorio não é um DAO, pois o Dao existe apenas para aquilo que é persistido.

Sobre a diferença entre “Repository” e “Repositorio” não vejo o ponto. É como dizer que Estratégia não é uma boa tradução de Strategy. Alguns nomes são dificies de traduzir , por exemplo Singleton, mas repository não é um deles. O que é um repositorio ? O dicionário responde : Lugar onde se deposita ou guarda alguma coisa. Bem adquado, quanto a mim. Então qual o problema de usar Repositorio no nome da classe ? Para mim nenhum. As pessoas têm usado DAO e Service no nome desde sempre. Alguns até usam BO (Business Object) e até mesmo Entity (ProdutoEntity, em vez de Produto). nomes são nomes. Sim, existem formas mais simples e padronizadas, mas discutir de o repositorio deve ou não ter “Repositorio” no nome é uma questão abaixo de secundária. O principal é se o conceito é entendido.

3.O repositorio como objecto inteligente do dominio

De fato o repositório não serve apenas para criar queries. Isso é o fim do seu trabalho. O repositório pode realizar decisões (ifs) baseado nos parâmetros de pesquisa e/ou em parâmetros do sistema e de configuração. O ponto é que no fim de todas as decisões o resultado será uma instrução de pesquisa que será executada no interpretador.

  1. Preciso procurar tudo usando repositórios ?

A ideia do artigo é que coisas simples como listas que alimentam combos não precisa. O objeto pesquisador ( seja um action ou alguém na ui etc… ) poderia acessar diretamente o local onde estão os dados. O entitymanager ou o hibernate, etc…
O ponto aqui é entender que :“qualquer instrução de pesquisa é uma regra de negócio”. Este é o conceito básico que dá origem ao repositório. É por isso que a criação da instrução de pesquisa é isolada e desacoplada. É isso que o repositorio + queryobject+interpreter fazem. Então, se eu tenho uma simples pesquisa de estados isso é uma regra de negocio ? Afinal os estados são fixos (mentira, a lista muda no tempo) porque eu preciso de um repositório ? A moral é : não é fixo. Vai mudar. Não hoje, não amanhã, mas é passível de mudar. Caso mude é bom que esteja desacoplado. às vezes existem filtros que limitam os estados (conforme alguma regra de negocio, por exemplo, a empresa não trabalha com aqueles estados e por isso eles não aparecem, mas à media que a empresa cresce mais estados são adicionados - o mesmo ao contrário quando a empresa deixa de estar presente numa região). Portanto, em termos de design desacoplar nunca é um problema. Na prática dá um pouco mais de trabalho, mas não é tanto assim que vai impedir de usar. Fora que usando o Repositório e o Interpreter para uma entidade X qualquer o código já vai ficar desacoplado do EntityManager de qualquer jeito para o X, então porque não usar para o resto ?
E porque a organização de repositorios não necessáriamente é 1 para 1 com as entidades fica mais facil de agrupar as coisas e deixar o código limpo.

Por outro lado, pensemos o que significa deixar a camada de cima (action, ui, etc…) acessar o entityManager. O EntityManager está em qual camada ? Na de domínio ? Teoricamente sim, mas na prática não, porque é um objeto do application server. Ou seja, embora ele seja um DomainStore, vc ainda pode se preocupar com o fato de um dia, outro objeto ocupar esse lugar ( o session do hibernate, por exemplo, ou alguma API nova do futuro). Então o EntityManager deveria ser injetado na implementação do DomainStore da sua aplicação e não ser o DomainStore em si. Do ponto de vista de um bom design é isso. Mas nem sempre as pessoas querem seguir um bom design e preferem cortar caminho (cut corners).

Usar o entitymanager diretamente no repositório no papel de interpreter é possível e funciona, usado Criteria API para o papel de QueryObject. Seja com session ou seja com jpa é a mesma coisa porque esses frameworks ja implementam as peças necessárias. Então qual é o problema ? Acoplamento. O seu codigo de negocio está acoplado à tenologia. Se a tecnologia precisar mudar ( por exemplo, hibernate=> jpa 1 => jpa 2) será um inferno reescrever todas as regras outra vez. Desacoplando isso não será necessário.
Mas quem gosta de desacoplar ? Muito poucos. A desculpa é sempre a mesma “isso não vai mudar”. Se podemos ter certeza de algo é que sim vai mudar. Só não sabemos quando.

A historia mostra que vários sistema são abandonados porque o trabalho para os ajustar a novas tenologias é maior que fazer de novo. Isto é ótimo para quem faz software , mas não é ético. Ao fazer um novo software as regras de negocio já implementadas se perdem. Novos levantamentos são necessários. E eles sempre são incompletos. O ideal seria manter o core do sistema velho ( que é a camada de domínio) e alterar a tenologia em volta dele. Por isso que o desacoplamento é tão importante na camada de domínio e por isso que o Repositório existe. Caso contrário deixaríamos a UI executar as pesquisas no entitManager e pronto.

Como opinião geral e não em relação ao artigo em si, o que se vê é que as pessoas comprar a ideia que o repositório é diferente do DAO mas têm problemas em saber exatamente em quê e como eles são diferentes. O que leva a coisas estranhas como

E não é apenas o autor desse blog que incorre neste problema de “eu sei que é diferente, mas chamo a mesma coisa”. Para mim isso significa que não se sabe realmente poque é diferente.Ou seja, comprou-se a ideia do padrão, mas não se entende qual é o principio que lhe dá origem. todos os padrões nascem de princípios como o DRY ou o SRP por exemplo. O Repositório nasce do principio que todas a queries são regras de domínio. Se aceitamos isto como verdade e por consequência aceitamos o repositório como padrão válido e utíl, então não podemos violar esse principio depois quer na implementação do padrão ou dizendo que “às vezes não precisamos do repositório” pois seria equivalente a dizer que “nem todas as queries são regras de domínio” o que contraria o principio que aceitámos.

É tudo uma questão lógica. O objetivo do padrão é bem claro. O resto é aplicação de principio de SRP que leva ao desacoplamento e ao uso de outros padrões. Mas parece que as pessoas pararam no tempo e só conseguem ver uma forma de implementar tudo : interface+implementação . Esse é o padrão Service, e serve para muitas coisas, mas não para todas.

Que fique bem claro que qualquer critica que fiz aqui é em relação aos conceitos errados e não às pessoas que os divulgam.

Galera com fazer uma pesquisa usando criteria like??
a pesquisa seria essa, ele funciona normalmente só precisaria transformar em um
método genérico.

	public List<Usuario> listarUsuarioLikeNome(String texto) {
		sessao = HibernateUtil.currentSession();
		tx = sessao.beginTransaction();

		Criteria criteira = sessao.createCriteria(Usuario.class).add(
				Restrictions.ilike("nome", "texto%"));

		List<Usuario> resultados = criteira.list();

		if (resultados == null) {
			JOptionPane.showMessageDialog(null, "Nenhum registro encontrado!");
		}

		sessao.close();

		return resultados;
	}

[quote=sergiotaborda][quote=MarkKnopfler]Estou surpreso, perplexo e maravilhado. O que eu li agora foi realmente algo muito embasado, no qual eu nem havia parado para pensar. Fica aqui meus cumprimentos.

Aprendi trocentas coisas:

  • que estava usando DAO de uma maneira mecânica
  • que essa forma “consagrada” viola princípios FUNDAMENTAIS
  • que tenho que investir mais em livros em INGLÊS, porque em praticamente TUDO que se lê por aí em português, temos DAO’s que simplesmente criam os Criterias e delegam o trabalho pesado para o framework de ORM. Bem, isto seria na verdade um repositório sendo chamado de DAO, não seria? Claro, um repositório meio acoplado (acoplado e meio) com a infraestrutura do framework, e nada coeso (pois assume também as tarefas de incluir/atualizar/excluir), mas que por dentro a única coisa que faz é definir critérios de pesquisa (o resto delega para o ORM).

Cito este post: http://blog.aspercom.com.br/2009/08/11/repositorios-ddd/

É outro blog que gosto muito de ler. Queria saber a opinião do Sérgio sobre o que o cara diz ali. Para mim parece que se encaixa. Será?[/quote]

1.A mania de usar interfaces

Ora, imaginemos que o repositorio não é uma interfaces. É apenas uma classe normal implementada normalmente. O que ela teria ?


public class RepositorioProduto {

       private QueryInterpreter interpreter;

         public Repositorio  (QueryInterpreter interpreter){
                this.interpreter = interpreter;
     }

    public List<Produto> findDisponiveis(){

            QueryObject query = new QueryObject(); 
               query.add(new FieldCriteria("disponivel", Operator.Equals, true);

               return interpreter.execute(query);

   }
      

}

Dois componentes vitais do repositorio são o QueryObject (mais conhecido como Criteria, mas o nome do padrão é QueryObject) e o Interpeter que é um padrão associado ao queryObject que realmente executa a pesquisa.

O trabalho do repositório é apenas construir estes QueryObject. O exemplo que coloquei ali é trivial, mas a pesquisa pode ser arbitrariamente complexa.
Para injetar dependências se usa o construtor ou métodos set. A interface é irrelevante para este processo de injeção. A testabilidade é obviamente simples pois a necessidade de mock é nula.
Se ha algo a mocar é o interpretador não o repositório.

Porque o repositório precisaria de várias implementações ? Apenas se vc tiver dois ou mais conjuntos de regras para fazer as pesquisas. Mas isto faz sentido ? É como dizer que existem duas formas de pesquisar produtos disponíveis. Não faz sentido.
Mesmo que haja a necessidade de mudar a query porque o modelo mudou ou o negocio mudou Essa alteração é imediata e se reflete imediatamente no sistema. Não existe essa de “vamos fazer a regra hoje e amanhã não”.

O problema, como sempre, é que se confunde a implementação do repositorio com a implementação do DAO mesmo quando se diz que o repositorio e o dao são conceptualmente diferentes. Se são conceptualmente diferentes porque raios têm o mesmo tipo de implementação. Se vc for ver no livro do Eric Evans em nenhum momento o repositorio aparece como interface+implementação. Na realidade é ao contrário. Ele sempre aparece como uma classe concreta que tem uma dependência de uma interface ( que é o interpreter, mas o fowler chama de strategy e outros chamam de datamapper)

  1. Os nomes

A ideia de ter um repositorio de PedidosFaturados e ou outro de TodosOsPedidos é correta pois o Repositorio além de ser um objeto do dominio, ele é associado a Agregados. Agregados são entidades especiais que agregam em si muita informação na forma de composição (agregação) com outras entidades. Isto serve para provar que o repositorio não é um DAO, pois o Dao existe apenas para aquilo que é persistido.

Sobre a diferença entre “Repository” e “Repositorio” não vejo o ponto. É como dizer que Estratégia não é uma boa tradução de Strategy. Alguns nomes são dificies de traduzir , por exemplo Singleton, mas repository não é um deles. O que é um repositorio ? O dicionário responde : Lugar onde se deposita ou guarda alguma coisa. Bem adquado, quanto a mim. Então qual o problema de usar Repositorio no nome da classe ? Para mim nenhum. As pessoas têm usado DAO e Service no nome desde sempre. Alguns até usam BO (Business Object) e até mesmo Entity (ProdutoEntity, em vez de Produto). nomes são nomes. Sim, existem formas mais simples e padronizadas, mas discutir de o repositorio deve ou não ter “Repositorio” no nome é uma questão abaixo de secundária. O principal é se o conceito é entendido.

3.O repositorio como objecto inteligente do dominio

De fato o repositório não serve apenas para criar queries. Isso é o fim do seu trabalho. O repositório pode realizar decisões (ifs) baseado nos parâmetros de pesquisa e/ou em parâmetros do sistema e de configuração. O ponto é que no fim de todas as decisões o resultado será uma instrução de pesquisa que será executada no interpretador.

  1. Preciso procurar tudo usando repositórios ?

A ideia do artigo é que coisas simples como listas que alimentam combos não precisa. O objeto pesquisador ( seja um action ou alguém na ui etc… ) poderia acessar diretamente o local onde estão os dados. O entitymanager ou o hibernate, etc…
O ponto aqui é entender que :“qualquer instrução de pesquisa é uma regra de negócio”. Este é o conceito básico que dá origem ao repositório. É por isso que a criação da instrução de pesquisa é isolada e desacoplada. É isso que o repositorio + queryobject+interpreter fazem. Então, se eu tenho uma simples pesquisa de estados isso é uma regra de negocio ? Afinal os estados são fixos (mentira, a lista muda no tempo) porque eu preciso de um repositório ? A moral é : não é fixo. Vai mudar. Não hoje, não amanhã, mas é passível de mudar. Caso mude é bom que esteja desacoplado. às vezes existem filtros que limitam os estados (conforme alguma regra de negocio, por exemplo, a empresa não trabalha com aqueles estados e por isso eles não aparecem, mas à media que a empresa cresce mais estados são adicionados - o mesmo ao contrário quando a empresa deixa de estar presente numa região). Portanto, em termos de design desacoplar nunca é um problema. Na prática dá um pouco mais de trabalho, mas não é tanto assim que vai impedir de usar. Fora que usando o Repositório e o Interpreter para uma entidade X qualquer o código já vai ficar desacoplado do EntityManager de qualquer jeito para o X, então porque não usar para o resto ?
E porque a organização de repositorios não necessáriamente é 1 para 1 com as entidades fica mais facil de agrupar as coisas e deixar o código limpo.

Por outro lado, pensemos o que significa deixar a camada de cima (action, ui, etc…) acessar o entityManager. O EntityManager está em qual camada ? Na de domínio ? Teoricamente sim, mas na prática não, porque é um objeto do application server. Ou seja, embora ele seja um DomainStore, vc ainda pode se preocupar com o fato de um dia, outro objeto ocupar esse lugar ( o session do hibernate, por exemplo, ou alguma API nova do futuro). Então o EntityManager deveria ser injetado na implementação do DomainStore da sua aplicação e não ser o DomainStore em si. Do ponto de vista de um bom design é isso. Mas nem sempre as pessoas querem seguir um bom design e preferem cortar caminho (cut corners).

Usar o entitymanager diretamente no repositório no papel de interpreter é possível e funciona, usado Criteria API para o papel de QueryObject. Seja com session ou seja com jpa é a mesma coisa porque esses frameworks ja implementam as peças necessárias. Então qual é o problema ? Acoplamento. O seu codigo de negocio está acoplado à tenologia. Se a tecnologia precisar mudar ( por exemplo, hibernate=> jpa 1 => jpa 2) será um inferno reescrever todas as regras outra vez. Desacoplando isso não será necessário.
Mas quem gosta de desacoplar ? Muito poucos. A desculpa é sempre a mesma “isso não vai mudar”. Se podemos ter certeza de algo é que sim vai mudar. Só não sabemos quando.

A historia mostra que vários sistema são abandonados porque o trabalho para os ajustar a novas tenologias é maior que fazer de novo. Isto é ótimo para quem faz software , mas não é ético. Ao fazer um novo software as regras de negocio já implementadas se perdem. Novos levantamentos são necessários. E eles sempre são incompletos. O ideal seria manter o core do sistema velho ( que é a camada de domínio) e alterar a tenologia em volta dele. Por isso que o desacoplamento é tão importante na camada de domínio e por isso que o Repositório existe. Caso contrário deixaríamos a UI executar as pesquisas no entitManager e pronto.

Como opinião geral e não em relação ao artigo em si, o que se vê é que as pessoas comprar a ideia que o repositório é diferente do DAO mas têm problemas em saber exatamente em quê e como eles são diferentes. O que leva a coisas estranhas como

E não é apenas o autor desse blog que incorre neste problema de “eu sei que é diferente, mas chamo a mesma coisa”. Para mim isso significa que não se sabe realmente poque é diferente.Ou seja, comprou-se a ideia do padrão, mas não se entende qual é o principio que lhe dá origem. todos os padrões nascem de princípios como o DRY ou o SRP por exemplo. O Repositório nasce do principio que todas a queries são regras de domínio. Se aceitamos isto como verdade e por consequência aceitamos o repositório como padrão válido e utíl, então não podemos violar esse principio depois quer na implementação do padrão ou dizendo que “às vezes não precisamos do repositório” pois seria equivalente a dizer que “nem todas as queries são regras de domínio” o que contraria o principio que aceitámos.

É tudo uma questão lógica. O objetivo do padrão é bem claro. O resto é aplicação de principio de SRP que leva ao desacoplamento e ao uso de outros padrões. Mas parece que as pessoas pararam no tempo e só conseguem ver uma forma de implementar tudo : interface+implementação . Esse é o padrão Service, e serve para muitas coisas, mas não para todas.

Que fique bem claro que qualquer critica que fiz aqui é em relação aos conceitos errados e não às pessoas que os divulgam.[/quote]

Ótimos post, muitas informações conceitos aprendidos de muita importância…
sergiotaborda contribuiu muito com nosso conhecimento, obrigado!!

Olha parece que uma onda me pegou… puxa há uns dois anos venho estudando java ( em casa ), lendo este post aqui parece que venho fazendo as coisas… não errado mais poderia fazer de uma forma mais correta ( seria bom se houvesse código demonstrando a forma clássica que encontramos com maior facilidade e que acho que foi a que eu aprendi e Domain Store )

eu vim aprendendo…

public interface BaseDao<T, ID extends Serializable>  {
   public abstract T save(T entity);  
   public abstract T findByID(ID Id);
@Transactional(readOnly = true )
public class BaseDaoImp<T, ID extends Serializable> implements BaseDao<T, ID>, Serializable {
	
    private static final long serialVersionUID = 1L;
    private EntityManager entityManager;
    private Class<T> persistentClass;


    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }


    protected Query createQuery(final String ql) {
		return getEntityManager().createQuery(ql);
	}
	
    @Transactional(readOnly = false )
    public T save(T entity) {
    	try {
    	    getEntityManager().persist(entity);
            return (T) entity;			
		} catch (Exception ex) {
			getEntityManager().getTransaction().rollback();
			throw new Error("Ocorreu um erro durante a atualização.", ex);
		} finally {
			
		}    	
    }

Acima já li sobre que não devemos ter transações porque isto estaria nas classes de negocio

mais apos isto eu tenho para cada entidade do meu modelo uma classes

@Repository("estadoDao")
public class EstadoDaoImp extends BaseDaoImp<Estado, String> implements EstadoDao {
 }
@Repository("produtoDao")
public class ProdutoDaoImp extends BaseDaoImp<Produto, Integer> implements ProdutoDao {
 }

e etc… é isto que aprendi que não esta… nos conformes??? porque qdo acho q tô sabendo alguma coisa e que posso dizer “Hoje sei um pouco de Java” parece que não sei

Mais sem duvidas ( isto eu sei ) parabens ao Sergio