DAO

DAO

O padrão Data Access Object (DAO) é um padrão introduzido no ambiente JEE [3] para simplificar e desacoplar a interação das aplicações Java com a API JDBC.

O problema

A maioria (para não dizer todas) das aplicações de nível corporativo usam algum tipo de persistência de dados. Entre eles o mais usado é o Banco de Dados e a linguagem SQL é amplamente utilizada para comunicar com os sistemas gerenciadores de banco de dados. Java suporta esta necessidade desde cedo com o advento da API JDBC (Java Database Connectivity).

Antes do uso de Java em sistemas corporativos as aplicações eram majoritariamente escritas em linguagens orientadas a processo e a ordem e instruções SQL específicas continham regras de negócio. Ao passar esses sistemas para Java, essas regras não se poderiam perder e, ao mesmo tempo, há que se trabalhar com objetos. O padrão DAO visava originalmente encapsular esses conjuntos de códigos SQL que existiam em aplicações legadas[3]. Esse código continha regras tanto na pesquisa dos dados, tanto na edição dos dados. É comum ao inserir um determinado dado, ter que inserir ou atualizar outros.

Para projetos novos, que não dependem de código legado, JDBC é a escolha para comunicar com bancos dados. Contudo o uso de JDBC obriga as aplicações Java, a escrever SQL para comunicar com o gerenciador de bando de dados. Essa comunicação é feita utilizando o padrão Bridge em que a interface é Java e igual para todos os sistema de gerenciamento de bancos de dados e a implementação é específica de cada um encapsulada no conceito de driver. O problema é que nem todos os drivers JDBC suportam todos os tipos de instrução SQL, ou nem sempre com o mesmo dialeto. Alguns suportam operações que outros não. Java é orientado a objetos e mapear as propriedades dos objetos para tabelas utilizando SQL é processo chato, demorado, passível de erro e que ninguém quer repetir em diferentes pontos da aplicação.

Finalmente, nem todas as aplicações comunicam apenas com banco de dados. Algumas podem comunicar com servidores LDAP ou serviços externos Business-to-Business (B2B), por exemplo. Esta comunicação é muitas vezes elaborada depois que a aplicação está em produção substituindo o banco como fonte de dados. As API para comunicação com estes sistemas são diferentes do JDBC quem em termos de interface quer em termos de filosofia.

O problema tem na realidades três perspectivas:

  • Legado : Queremos encapsular lógicas de persistência legadas escritas com SQL ou outras tecnologias de forma simples. Queremos apenas utilizar as tecnologias java, mas manter as mesmas regras de negocio
  • Isolamento : Queremos que a aplicação seja isolada da API com que está comunicando. Queremos poder alterar a API sem alterar a aplicação. No caso de JDBC queremos utilizar a mesma API para comunicar com diferentes gerenciadores de bando de dados sem alterar a aplicação.
  • Mapeamento de Objetos : Qeremos utilizar objetos no ambiente Java. Queremos poder utilizar os mesmos objetos independentemente da API de persistencia.ORM (Object-Relational Mapping) – Mapeamento Objeto-Relacionamento é o mapeamento mais comum, mais outros mapeamentos são possiveis, como para XML, LDAP ou WebServices. Os mapeamentos ORM podem ainda mudar quando mudamos de gerenciador de banco de dados

A solução

O padrão DAO soluciona estes problemas de uma forma simples. Todas as comunicações com o mecanismo de persistência são mediadas por um objeto o DAO. Esse objeto mapeia informações transportadas em objetos (Tranfer Object) para instruções da API de persistência e mapeia resultados obtidos dela de volta para os mesmos objetos de transporte. Toda a lógica de mapeamento e execução das instruções é deixada dentro do objeto DAO desta forma isolando a aplicação da API de persistência por completo.

O objeto DAO é responsável por operar o mecanismo de persistência em nome da aplicação tipicamente executando os quatro tipos de operações – Criar, Recuperar , Alterar, Apagar – conhecidas pela sigla CRUD – do inglês Create, Retrive, Update , Delete. As operações de edição são invocadas diretamente passando o objeto com as informações a serem editadas.
As operações de recuperação são normalmente implementadas como métodos específicos. Por exemplo, recuperar o objeto que corresponde com uma certa chave, ou critério de busca. Estes métodos contém regras de negocio diferentes conforme o tipo de dados sendo persistido. Em particular pode não existir nenhuma regra particular, ou a regra só poder ser executada em um tipo especifico de API de persistência.

Interface

É interessante que o DAO seja especificado através de interface ao invés de uma classe concreta. Desta forma, não só facilitamos o trabalho de implementar novos mecanismos de persistência, mas também, impedimos que se criem referencias a classes concretas, diminuindo o acoplamento a um mecanismo em particular.

Se estamos utilizando diferentes DAO conforme o mecanismo de persistência que queremos usar, temos que ter alguma forma de escolher qual utilizar. Se você estiver utilizando algum framework de injeção de dependência (DI), basta configurá-lo para injetar a implementação certa. Outra opção (que não é incompatível com a anterior) é o uso do padrão Factory Estes padrões funcionam melhor se utilizarmos interfaces seguindo o Principio de Design por Contrato.

A interface do padrão original é simples. São fornecidos métodos para as operações CRUD, sendo que a operação de recuperação é distribuída em diferentes métodos de pesquisa especializados. São estes métodos especializados que encapsulam facilmente lógicas de pesquisa de sistemas legados.

01
02
03 public class Customer {
04 // atributos
05 // acessores e modificadores
06
07 }
08
09 public interface CustomerDAO {
10
11 Customer create () ;
12 void insert ( Customer c ) ;
13 void update ( Customer c ) ;
14 void delete ( Customer c ) ;
15 Customer findByID ( Integer id ) ;
16 Customer finfByCustomerNumber ( String customerNumber ) ;
17 }
18
19 public class JDBCCustomerDAO implements CustomerDAO {
20
21 public Customer create (){
22 return new Customer () ;
23 }
24 public void insert ( Customer c ){
25 // usa JDBC para criar e executar uma frase SQL de insersão.
26 }
27 public void update ( Customer c ){
28 // usa JDBC para criar e executar uma frase SQL de atualização.
29 }
30 public void delete ( Customer c ){
31 // usa JDBC para criar e executar uma frase SQL que remove o cliente do banco
32 }
33 public Customer findByID ( Integer id ){
34 // usa JDBC para criar e executar uma frase SQL que pesquisa o cliente com a chave passada.
35 }
36 public Customer finfByCustomerNumber ( String customerNumber ){
37 // usa JDBC para criar e executar uma frase SQL que pesquisa o cliente com o numero passado.
38 }
39 }

Código 1:

O mesmo código teria que ser repetido para todos os tipos de objeto persistido.

Coloquei o método create() explicitamente na interface do DAO porque será importante mais à frente. Por agora ele simplesmente cria o objeto algo que poderíamos fazer facilmente fora do DAO. Esta utilização do padrão Factory Method parece fútil, mas como veremos depois é importante para alguns tipos especiais de implementação do padrão DAO.

Sabores de DAO

Existem vários “sabores” de DAO. A razão para isto é que o padrão DAO não é muito prático quando o sistema tem muitos objetos persistentes.

DAO padrão

Vimos como seria a implementação padrão[3] do DAO. Para cada tipo de objeto de transporte (TO) – Cliente, Pedido , etc… – existe um objeto DAO correspondente. Os objetos DAO formam uma camada na aplicação[1]. A aplicação tem que invocar o DAO certo para trabalhar com o objeto de transporte certo. Cada objeto DAO sabe como ler e popular as propriedades do TO e usá-las na API do mecanismo de persistência que está usando.

Neste sabor do padrão os objetos DAO formam um camada espessa recheada de lógica de mapeamento misturada com lógica de persistência e lógica de negócio. Além disso ele cria a necessidade de um conjunto muito grande de classes distribuídas no seguintes tipos:

  • TO – Objetos de transporte. Eles são encarregados de manter os dados em memoria na forma de objetos e estruturas de objetos. Exemplo: Customer
  • Interface DAO – Interface para o DAO de um certo tipo de TO. Exemplo: CustomerDAO
  • Implementação DAO – Implementação da interface para o DAO de um certo tipo de TO e um certo tipo de API de persistência. Exemplo: JDBCCustomerDAO
  • Factory de DAO – Fabrica que sabe qual implementação utilizar para cada interface. Na realidade a fabrica é uma metáfora para o mecanismo de mapeamento entre a interface e a implementação. Utilizando um mecanismo de DI teríamos de as mapear igualmente, apenas o faríamos de forma diferente.

Se o seu sistema tiver 10 tipos de objeto persistente (10 tabelas) você precisa escrever 30 classes só para começar.

DAO Genérico

Você pode estar pensando que usando tipos genéricos poderíamos diminuir a quantidade de interfaces e implementações necessárias. Na realidade isso não é bem verdade, porque as interfaces do DAO contêm métodos de procura específicos dependentes do objeto de transporte , das regras de persistência e de regras de negocio.

Usando tipos genéricos neste estágio não nos ajuda a diminuir o número de classes ou simplificar a implementação mas no ajuda a diminuir o numero de métodos por interface DAO utilizando interfaces comuns (padrão Separated Interface [1]).

01
02
03 public interface GenericDAO<T> {
04
05 T create () ;
06 void insert ( <T> obj ) ;
07 void update ( <T> obj ) ;
08 void delete ( <T> obj ) ;
09 T findByID ( Integer id ) ;
10
11 }
12
13 public interface CustomerDAO extends GenericDAO<Customer> {
14
15 Customer finfByCustomerNumber ( String customerNumber ) ;
16 }

Código 2:

Diminuimos a quantidade de métodos na interface DAO especifica de cada objeto de transporte, mas não ganhamos muito. Criamos mais uma classe e a implementação ainda continua específica.

DAO + Bridge

Até agora deixamos os objetos de transporte serem explicitamente classes. Isto é na realidade um problema. Todas as implementações do DAO para as várias tecnologias estão forçadas a utilizar o mesmo objeto. Se o objeto mudar (por exemplo, adicionarmos um campo) todas as implementações de DAO para as várias tecnologias têm que mudar. Para evitar este problema aplicamos o padrão Bridge deixando as implementações e as interfaces serem definidas independentes.Para isso utilizamos interfaces em vez de classes para especificar os nossos objetos de transporte[3].

Como estamos utilizando o padrão Factory Method para obter os objetos de transporte, podemos agora retornar uma implementação especifica da implementação do DAO. Com isto podemos fazer muitos tipos de otimização. Por exemplo, podemos incluir uma lógica que nos permite saber se os valores dos dados mudaram. Isso ajudará no método de atualização. Se não mudou nada simplesmente não faz nada e poupa a comunicação com o banco. Quando a implementação controla todos os fatores é fácil fazer otimizações. Esta técnica é utilizada pela própria API JDBC para desacoplar a aplicação Java do gerenciador de banco de dados permitindo que este faça as otimizações que achar necessárias.

DAO + Bridge + Proxy

Como não existe nenhuma outra lógica nos objetos de transporte que não seja ler e escrever os seus atributos podemos utilizar uma implementação genérica baseada num mapa atributo=valor utilizando o padrão Proxy. Basicamente utilizamos um Map e o encasuplamos dinamicamente na interface do objeto de transporte esperado. Isto é relativamente simples de fazer utilizando a classe java.lang.reflect.Proxy da API padrão do JSE.

A utilização do padrão Bridge não nos ajuda a diminuir classes, mas ajuda na implementação. Podemos ter controle total sobre como implementamos os objetos DAO e como comunicamos com a API de persistência. Isso permite que utilizemos otimizações, entre as quais o uso de Proxy para os objetos de transporte. Retirando efetivamente da aplicação o trabalho de os codificar e manter.

DAO + Metadados

Para reduzir o número de implementações necessárias, ou pelo menos diminuir a implementação de métodos comum é necessário termos a informação descrita de uma forma mais abstrata. Temos que utilizar metadados.

Existem dois tipos de metadados que podem ser usados, não necessariamente excludentes.
Podemos utilizar metadados existentes na própria estrutura das classes. Este uso é normalmente referido como Introspecção (Introspection é um tipo particular de Reflection) Por exemplo, não usar new na classe e usar os mecanismo de do Java para criar o objeto a partir da sua classe. ( se utilizarmos o mecanismo de proxy descrito antes já estaremos fazendo isto implicitamente) Outro exemplo é utilizar introspecção para ler e escrever os atributos dos objetos dinamicamente invocando os métodos get/set dinamicamente. Para que o mecanismo de introspecção funcione a implementação do DAO precisa previamente saber a classe do TO.

Outra forma de metadados são aqueles relacionados à estrutura persistente do objeto. No caso de bancos de dados seriam os metadados das tabelas e seus relacionamentos.

Podemos deixar à responsabilidade da implementação do DAO descobrir e utilizar os metadados. Uma melhor opção é utilizar o padrão MetadataMapper deixando essa responsabilidade para outro objeto. Este objeto pode simultaneamente obter informações da estrutura de classes como ser configurado com informações extra sobre relacionamentos e tabelas.

Com metadados a implementação dos métodos básicos é comum a todos os tipos de objeto de transporte, simplificando a implementação do DAO. Essas implementações comuns podem ser encasupladas num classe pai de todos os DAOs. Os DAO específicos podem estender esta classe se necessário para prover mais mecanismos de busca, ou alterar os mecanismos padrão.

01
02
03 public class AbstractDAO<T> implements GenericDAO<T> {
04
05 MetadataProvider metadata;
06 public AbstractDAO ( MetadataProvider metadata ){
07 this .metadata = metadata;
08 }
09
10 public T create (){
11 return metadata.getTOClass () .newInstance () ;
12 }
13
14 public T findOne ( QueryObject<T> q ){
15 // traduz q para SQL usando os metadados
16 }
17
18 …
19 }

Código 3:

O número de classes diminuiu. Agora podemos utilizar sempre AbstractDAO apenas constituindo classes especificar quando existem métodos ou regras especificas a serem implementadas. A utilização de fabricas ou DI é vital para o sucesso desta abordagem porque podemos retornar uma instância de AbstractDAO  devidamente configurada para um TO particular. Apenas em casos particulares precisaremos retornar alguma classes especial. E quando tivermos que fazer isso poderemos aproveitar a maioria dos métodos via herança.

DAO + QueryObject

Aquilo que separa ainda de implementações ainda mais genéricas para o padrão DAO são os métodos especiais de pesquisa. Criar um método para cada estratégia de pesquisa aumenta rapidamente a interface do DAO. Isso é mau pois estamos aumentando a responsabilidade dos implementadores da interface. Isso obriga a que todos os DAO de todos os mecanismos implementem esses métodos. Inadevertidamente podemos criar métodos que certos tipos de persistencia não podem executar. Mesmo com o padrão Bridge, isso pode ser complicado de gerenciar.

Para solucionar isso podemos invocar o Principio de Separação de Responsabilidade (SoC) e abstrair a logica de pesquisa num objeto à parte. Estas várias estratégias de pesquisa podem ser utilizadas por DAO de diferentes tipos e até mesmo para diferentes mecanismos de persistencia.

Em particular podemos criar implementações de Query Object que permitam as operações mais comuns. Deixando para os métodos especiais apenas aquelas que não podem ser traduzidas pelo Query Object. Sendo que SQL é uma linguagem de pesquisa genérica é normalmente possível explicitar a maioria das opções utilizando uma implementação de Query Object O numero de métodos específicos que ainda teriam que ser criados nas interfaces especificas dos DAO diminuem na razão inversa do poder de abstração da sua implementação de Query Object.Ou seja, quanto mais poder usar Query Object menos usará métodos específicos.

01
02
03 public interface GenericDAO<T>> {
04
05 T create () ;
06 void insert ( <T> obj ) ;
07 void update ( <T> obj ) ;
08 void delete ( <T> obj ) ;
09 List<T> findAll ( QueryObject<T> criteria ) ;
10 T findOne ( QueryObject<T> criteria ) ;
11 }
12
13 DAO Genérico com QueryObject

Código 4: DAO Genérico com QueryObject

A utilização destes objetos de pesquisa pode facilmente distribuir logicas de pesquisa por toda a aplicação. Para que isso não acontece você pode utilizar o padrão Repository que mantém as pesquisa num só lugar.

O uso de Query Object simplifica a interface do DAO diminuindo o numero de métodos de pesquisa especificos.

Referências

[1] Patterns of Enterprise Application Architecture
Martin Fowler et. al.
URL: http://www.martinfowler.com
[2] Design Patterns: Elements of Reusable Object-Oriented Software
Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides
URL: 1995
Addison-Wesley
[3] Core J2EE Patterns – Data Access Object
Sun Developer Network
URL: http://72.5.124.55/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

Licença

Creative Commons License Sérgio Taborda
Este trabalho é licenciado sob a
Licença Creative Commons Atribuição-Uso Não-Comercial-Não a obras derivadas 3.0 Genérica .

12 opiniões sobre “DAO”

  1. Sergio,

    interessante seu artigo. Só não entendi uma coisa, em um forum do GUJ, vc diz que é um erro o uso do Hibernate como uma possivel implementação do DAO.

    Eu não entendi pq vc afirmou isso ainda mais após ler esse seu artigo que diz que uma das motivações de se utilizar o DAO é abstrair a parte de mapeamento de objetos.

    Outra coisa, na sua opinião, será que realmente ter esses DAOs extremamente genéricos, usando metadados e outros recursos, reduzindo a quantidade de classes de implementação? Acho que o código fica complicado de entender e com certeza não deve ser tão performático quanto escrevendo DAOs específicos para cada entidade.

    Enfim, qual cenário seria interessante usar essas implementações genéricas?

    Outra coisa, na sua opinião, será que realmente vale a pena ter esses DAOs extremamente genéricos, usando metadados e outros recursos, reduzindo a quantidade de classes de implementação? Acho que o código fica complicado de entender e com certeza não deve ser tão performático quanto escrevendo DAOs específicos para cada entidade.

  2. O erro de embrulhar o Hibernate com o DAO é conceptual. O hibernate é uma implementação do padrão DomainStore. Este padrão visa simplificar a persistencia de um modelo de dominio OO. O DAO não visa isso. Ele visa simplificar a comunicação com uma API de persistencia. Isso inclui, por exemplo, a chamada a sotreprocedures de forma transparente que não é o objetivo do DomainStore. Ao colocar o DomainStore dentro do DAO vc está tentando criar um forno a lenha que usa na realidade um micro-ondas internamente. não faz sentido esse tipo de encapsulamento. O DAO não serve para abstrar Mapeamento OR – embora possa – ele serve para abstrair o acesso a dados ( quaisquer dados, em qualquer formato, não necessariamente OO).
    O objetivo é não criar um DAO para cada entidade. Isso é prolixo e no fim, inútil. O código dentro dessas classe é sempre igual …. Por isso o DomainStore apareceu (naturalmente como evolução do DAO). Ele já sabe que o código é sempre o mesmo e fornece mecanismos para que vc não tenha que o escrever. Assim o DAO sobra apenas como um padrão de importância histórica e sempre que vc tiver uma comunicação com sistemas legados cuja interface é através de um banco de dados (que foi o problema que levou, inicialmente, ao uso e criação do padrão DAO).
    Tentei demonstrar no artigo que podemos entender o DomainStore como uma evolução natural do DAO mas que chegado em certo ponto é necessário injetar conhecimento do domínio. É ai que a responsabilidade do DAO é quebrada porque ele não pode saber do domínio. Então o objeto de acesso a dados se torna no objeto de acesso a entidades de um domínio persistidas em algum armazém (store) o Data Access Object vira o Domain Store que é um objeto com responsabilidades diferentes.

    Na minha opinião , se o seu sistema não interage com sistemas legados , vc deve esquecer que existe o DAO. Deve simplesmente usar um DomainStore ( tem alguns já implementados como o Hibernate ou o JPA, ou fazer o seu) para o acesso persistente e um camada de Repositórios para incluir as lógicas. Aqueles métodos que vc coloca no DAO para montar uma query , enviá-la ao banco e tratar o resultado de forma a ser devolvido num objeto simples ( um List,por exemplo) deve ser feito no Repositório. Ele usa a API de critérios do DomainStore que é equivalente a escrever SQL, envia ao DomainStore e ele lhe retorna o resultado que vc então trata para retornar o que vc quer (um List, normalmente)

    Só existe uma única razão para usar DAO: acessar um sistema legado.

    Dê uma olhada no artigo Arquitetura Orientada ao Domínio para mais detalhes.

  3. Bom dia Sergio,
    No que você colocou !!!

    “O DAO não serve para abstrar Mapeamento OR – embora possa – ele serve para abstrair o acesso a dados ( quaisquer dados, em qualquer formato, não necessariamente OO).”

    Pergunto,

    O DomainStore diz respeito a entidades ? posso dizer que essas entidades são objetos de infraestrutura(usam mecanismo de frameworks), em vista que você já afirmou que o DAO seria uma classe abstrata ou até mesmo o repositório, todavia o DAO recupera informações de dados, esse dados são entidades que diz respeito a Dominio para que contexto não diz respeito mas o DAO acessa sistema legado usando que mecanismo o DomainStore.

    Talvez eu tenha feito uma salada de ideias, mas no fim quero saber se existem objetos de dominio e se são entidades e se existem objetos de infraestrutura se são o DomainStore, ou se o termo que estou querendo empregar é equivocado ou estou fazendo confusão sobre conceitos.

    Abraçosss

    1. Um domainStore é um “armazém de dominio”. Essa é a tradução literal que encaixa muito bem. O DomainStore guarda entidades do dominio. Entidades são do dominio. Não são de infraestrutura. Mesmo que o seu DOmainStore seja implmentado por um API de terceiros ela não cabe como infra. Dados não são entidades. São dados: numeros, palavras, datas. Entidade é algo mais. É ter uma identidade. Ser único no sistema. Pessoas podem ter os mesmos dados ( mesmo nome, data de nascimento) e mesmo assim serem diferentes pessoas. Entidade é um conceito abstrato que pertence ao dominio. Dado é um conceito concreto que pertence à aplicação.
      DAO não usam DomainStore. DomainStore é que usa DAO ( internamente) O acesso a sistemas legados só pode ser feito se o sistema legado é OO e contém o conceito de dominio. Caso contrário é um sistema orientado a dados e o DomainStore é inutil.

      Objetos de Dominio são todos aqueles que participam do dominio. Existem vários. Cada uma com responsabilidades diferentes. Eles implementam vários padrões como Entidade , Serviço, Objecto de Valor, Repositorio e Validador. A implmentação destes pode ser feita à custa de API já existentes, mas isso não os torna objetos de infra. Entidades são objetos de dominio, mas nem todos os objetos de dominio são entidades. Alguns são serviços, por exemplo.

      1. Excelente explicação Sergio, !!!!

        Mas questionando um pouco mais, o que eu poderia relevar a objetos de infra ? Poderiam ser componentes ?!isso não se encontra dentro da minha aplicação ?!

        Em outra questão você colocou Entidades são objetos de dominio, mas nem todos os objetos de dominio são entidades.Alguns são serviços.Quando você se reporta a serviços é algo sobre SOA ?

        + uma vez Obrigado !!!!

      2. Objetos de infra fazem coisas tão genéricas que servem para todas as aplicações. Por exemplo, um servlet é um objeto de infra.
        SOA é uma camada de serviços de aplicação. Uma aplicação fornece serviços para outra. Serviços de dominio é algo mais interno.
        Um webservice, por exemplo, é um serviço de aplicação. Internamente ele pode invocar um serviço de dominio ou vários. Ha uma relação entre os dois tipos de serviço, mas não é 1 para 1.

      3. Obrigado Sergio,

        Agora ficou melhor esclarecido, são esses detalhes que agente não percebe e que fazem muita diferença no entendimento !!!

        Abraçãooo !!!

  4. sergiotaborda :
    Objetos de infra fazem coisas tão genéricas que servem para todas as aplicações. Por exemplo, um servlet é um objeto de infra.
    SOA é uma camada de serviços de aplicação. Uma aplicação fornece serviços para outra. Serviços de dominio é algo mais interno.
    Um webservice, por exemplo, é um serviço de aplicação. Internamente ele pode invocar um serviço de dominio ou vários. Ha uma relação entre os dois tipos de serviço, mas não é 1 para 1.

    Sérgio parabéns, acompanho sempre no GUJ e no seu BLOG tuas articulações acerca de arquitetura, pattern’s, metodologias, paradigmas, efim parabéns, considero você um gênio e bastante conheçedor principalmente de padrões de projeto, inclusive os do Domain Driven Design. Efim as minha perguntas são simples:

    1. Levando em conta que o Hibernate é uma implementação da API de persistência do JAVA ou JPA, assim como outros providers de ORM, posso afirmar que internamente tais providers implementam o padrão DomainStore ?

    Exemplo:

    //Esse também é artefato de dominio.
    Tenho a Entidade Cliente.java, essa por sua vez possui seguinte regra de negocio.

    public class Cliente {

    //O Spring injeta prá mim a implemetação que no caso está na camada de infra ou //seja o DAO podre que você fala para cada entidade.
    private ClienteRepository clienteRepository;

    public List obterContasReceber(Date dataInicial, Date dataFinal) {
    if(dataFinal.before(dataInicial)) {
    thow new exception(“Data final deve ser maior que inicial”);
    }

    //O Rodrigo Yashima questionou no blog dele acerca de prefixar nome do
    //repositorio com “repository”. segundo ele, prá denotar a realidade do
    //do dominio deveria chamar “Clientes” pois trata de repositorio de clientes
    //Também concordo, até prá preservar a Linguagem Onipresente que prega o DDD
    return this.clienteRepositoty.obterContasReceber(dataInicial,dataFinal);
    }

    }

    Repositorio de Cliente.

    //Esse cara é artefato de dominio.

    public interface ClienteRepository {

    public List clienteenteRepositoty.obterContasReceber(dataInicial,dataFinal);

    }

    ================================================================================

    //Arqui vem a bagulhada de infra.
    //Não sou muito fã de Generic’s e Reflection’s. o tipo da list poderia ser T
    public class ClienteDAOImp implements ClienteRepository {

    public List obterContasReceber(dataInicial,dataFinal) {
    //Empreender toda logica prá acessar o SGBD..e retornar os objetos
    //Para as camadas que impusionaram a chamada.
    }

    }

    Eu tinha té criado uma interface IClienteDAO que fosse implementada por essa classe ClienteDAO, visando abstrair o SGBD, entretanto, com lendo sobre DDD, vi
    que isso não é necessário uma vez usando esse padrões. Agora vem a pergunta Sergio,
    Eu posso elimiar esse nome “DAO” mesmo usando SQL Puro..? ficaria assim.

    //Arqui vem a bagulhada de infra.
    //Não sou muito fã de Generic’s e Reflection’s. o tipo da list poderia ser T
    public class ClienteRepositoryImp implements ClienteRepository {

    public List obterContasReceber(dataInicial,dataFinal) {
    //Empreender toda logica prá acessar o SGBD..e retornar os objetos
    //Para as camadas que impusionaram a chamada.
    }

    }

    Ou seja, ao invés de chamar ClienteDAOImp, se chamada ClienteRepositoryImp e herda/implementa de ClienteRepository agora te pergunto, esse ClienteRepositoryImp ficaria na camada de infra ou domain ?

    Observe que estou a utilizar JDBC puro sem framework nenhum de ORM,. seria correta deixar a implemetação do repository que nada mais é que um DomainStore, por exemplo um EntityManager da JPA é um objeto do DomainStore concorda? ou seja, deixar essa implementação dentro do Domain Model ? e eliminar esse objeto DAO ?

    tem como você citar exemplos? Se possivel envie um diagrama de sequencia de uma caso de uso qualquer.que use JDBC puro sem ORM.

    sfidencio@gmail.com

    Att
    fidêncio.

    1. sfidencio, peço desculpa porque só vi a sua pergunta hoje. De alguma forma escapou nos avisos do wordpress. O problema que coloca é relativo a repositorios que usam SQL puro por baixo dos panos. Em tese um repositorio pode usar qualquer tecnologia que quiser , mas não diretamente. Normalmente o Repositorio delega ao DomainStore que por sua vez delega a objetos internos que chamam o banco de dados. O repositorio não é uma interface, é uma implmentação concreta e única. O objetivo do repositorio é encapsular todas as logicas de pesquisa. Ou seja, seus metodos são coisas como obtemProdutosVendiddosNosUltimosMeses(int quantidadeDeMEses): List , obtemClienteQueCompraramOProduto(Produto p), etc… ninguem acima do repositorio sabe como é feita a pesquisa. O repositorio pode ser implementado de várias formas, mas a forma escolhida não muda no tempo ( ao contrario do DAO). Se quer usar SQL puro, vc precisa encapsular a escrita do SQL em uma outra camada e fazer o repositorio chamar essa camada. O Repositorio não pode escrever SQL. Você precisa usar Query Objects, ou seja precisa – de uma forma simplificada – isolar o que é o critério de como ele se executa. O repositorio só decide qual é o critério, não como ele é executado.
      O EntityManager é um DomainStore, o Session do Hibernate é um DomainStore, Os objetos de Criteria do Hibernate são Query Objects e no JPA (2.0) também é possivel escrever as queries em objetos. A ideia é que o repositorio, ao contrario do DAO, não sabe e não quer saber como a pesquisa é efeita na realidade, mas eles quer dizer qual é a regra. Por exemplo “pesquisa na tebela X pelo campo A e encontre todos os elementos em Y cujo campo B é igual a A” esta é a regra de neogico. E é isto que fica no repositorio. A regra, não a implementação da execução. Um criterio como este pode ser executado como um SQL, mas também pode ser executado com for em cima de coleções, já que o Repositorio não sabe onde as informações estão de fato. Isso quem sabe é o DomainSotre, ou uma camada de DAO. No seu caso parece mais simplesmente implementar o SQL no repositorio, mas isso não é a implementação do padrão Repositorio, e sim a implementação do padrão DAO. Para mais informações sobre a arquitetura de Repositorio e Query Object leia este artigo

  5. Sérgio sei que o post é antigo (mas é muito bom), mas tenho uma dúvida que persite… Venho do PHP e lá para mim era comum um DAO acessar outro DAO (da mesma interface (SqlServer, mysql…)), só que um amigo meu disse que jamais faria isso, ele disse que usaria um Service(não conheço esse padrão). De qualquer forma ele não soube me explicar porque um DAO não pode acessar outro… Qual sua opinião? Você poderia fazer uma materia sobre Service(caso exista claro)?

    1. Obrigado por ler o blog e por seus comentários.
      Não ha problema de uma implementação de um DAO usar outra implementação de DAO (até mesmo se não for da mesma familia). Por exemplo, vc pode ter dois bancos (um legado, e um moderno) e ter que misturar as queries nos dois, ou persistir coisas em ambos ao mesmo tempo. Não ha problema. Claro que é um inferno controlar isso, mas a dependência em si não é contra as regras.
      Sobre Service leia http://www.javabuilding.com/search/academy/patterns/service.html. Mais sobre DAO em http://www.javabuilding.com/search/academy/patterns/dao.html. Já agora, para contuedo mais atualizado, acompanhe meu novo blog em e dê uma navegada no http://www.javabuilding.com

      O DAO é uma especialização do padrão Service. Ou seja, todo o DAO é também um service. Só que é um service com um fim especifico (acessar dados). Portanto, diga para seu colega que se é válido para service, é válido para dao 🙂

Deixe um comentário