Pedro Jefferson
Header

Dao vs Repository

Por Pedro Jefferson

Dando uma caminhada pela internet me deparei com essa explicação muito boa sobre DAO e Repository no Stack Overflow. Como diversas vezes tenho esse tipo de duvida decidi publicar pois pode ajudar mais pessoas. Essa explicação foi de @utluiz e a thread você pode conferir clicando aqui.
O blog dele é o http://luizricardo.org/

TL;DR

DAO e Repository são dois padrões de projetos importantes, cujos propósitos tem uma pequena área de intersecção. Porém, como veremos abaixo, eles diferem tanto em seus objetos, quanto em sua origem e implementação. DAOs lidam diretamente com a fonte de dados e abstraem as operações realizadas nela. Repositórios provêm uma interface para tratar o armazenamento e recuperação de entidades do domínio como uma coleção.

DAO vs Repository

DAO e Repository são dois padrões de projetos importantes, cujos propósitos tem uma pequena área de intersecção. Porém, como veremos abaixo, eles diferem tanto em seus objetos, quanto em sua origem e implementação.

DAOs lidam diretamente com a fonte de dados e abstraem as operações realizadas nela. Repositórios provêm uma interface para tratar o armazenamento e recuperação de entidades do domínio como uma coleção.

DAO

Um Data Access Object (Objeto de Acesso a Dados) é um objeto que provê uma interface abstraindo um banco de dados ou algum outro mecanismo de persistência externo à aplicação. Objetivos:

  1. Encapsulamento: não expor detalhes da fonte de dados para o resto da aplicação
  2. Princípio da responsabilidade única: ser o único lugar que trabalha com SQL ou dialeto específico daquela fonte de dados
  3. Satisfazer necessidades específicas da fonte de dados: mapear devidamente as estruturas de dados ou objetos da aplicação de acordo com os tipos e estruturas específicas da fonte de dados

Exemplo:

interface ClienteDao {
    void incluir(Cliente)
    void atualizar(Cliente)
    void atualizarUltimoAcesso(Integer,Date) //atualiza um campo
    Cliente recuperar(Integer)
    Cliente[] listarPorNome(String)
    ...
}

Em resumo, um método de um DAO segue o modelo:

umMetodoQualquerQueAbstraiUmaQueryEspecifica(ParametrosDaQuery)

Geralmente, cada método de um DAO executa uma única operação de leitura ou escrita no banco de dados.

Repository

Um Repository Repositório é um objeto que isola os objetos ou entidades do domínio do código que acessa o banco de dados.

Temos que um repositório implementa parte das regras de negócio no que se refere à composição das entidades. Ele é fortemente vinculado ao domínio da aplicação e este é um reflexo direto das regras de negócio, pois ele abstrai armazenamento e consulta de um ou mais entidades de domínio.

Entretanto, não podemos confundir isso com as regras de negócio no sentido de processamento das informações. Um repositório não deve incluir as regras de negócio no sentido de tomar decisões, aplicar algoritmos de transformação dos dados ou prover serviços diretamente a outras camadas ou módulos da aplicação. Mapear entidades de domínio e prover as funcionalidades da aplicação são responsabilidades distintas.

Um repositório fica entre as regras de negócio e a camada de persistência:

  1. Ele provê uma interface para as regras de negócio onde os objetos são acessados como em uma coleção.
  2. Ele usa a camada de persistência para gravar e recuperar os dados necessários para persistir e recuperar os objetos de negócio.

Portanto um repositório pode, inclusive, fazer uso de um ou mais DAOs. A interface de um repositório muitas vezes é análoga à interface de List do Java ou C#, provavelmente com a exceção dos métodos de pesquisa.

Exemplo:

interface ClienteRepository {
    void persistir(Cliente)
    Cliente recuperar(Integer)
    List<Cliente> pesquisar(TermosDaPesquisa)
    List<Cliente> todos()
}

No exemplo acima, num cenário mais simples, ClienteRepositorypersistir() pode fazer uso do método ClienteDao.incluir(). Porém, ele pode também verificar se o cliente já existe e, neste caso, usar o método ClienteDao.atualizar(). Indo mais além, se Cliente é uma entidade de domínio mais complexa ele poderia carregar uma lista de endereços a partir de outro DAO.

Enfim, repositórios não contém regras de negócio, mas contém lógica para construir e persistir corretamente os objetos de domínio.

Frameworks ORM

Frameworks como Hibernate (Java) ou NHibernate (.NET)disponibilizam uma interface bem mais próxima ao padrão Repository porque:

  1. Trabalham com coleções. Vide métodos persist() e find().
  2. As pesquisas são realizadas por uma interface independente do tipo de banco de dados.
  3. Realizam o trabalho de construir e armazenar as entidades da aplicação, inclusive com a possibilidade de recuperar valores de relações automaticamente, como no exemplo acima sobre a lista de endereços do cliente.

Além disso, eles também fazem o papel do DAO, pois:

Em contrapartida, é claro que tais frameworks sem sempre conseguem substituir completamente um repositório específico da aplicação por serem muito genéricos. Então, mesmo ao usar um ORM, pode ser interessante não misturar suas regras de negócio com código específico do framework. Neste caso, criar Repositórios que fazem uso do framework faz sentido, como se fosse um DAO++, afinal você está num maior nível de abstração e não está abstraindo o acesso à fonte de dados.

Quando usar os padrões

O uso de DAOs é praticamente uma necessidade se você não usa ORMs, mesmo que você use outra nomenclatura, afinal você precisa de um lugar para colocar o código SQL. Repositórios, por outro lado, são interessantes para aplicações um pouco maiores, onde o custo de adicionar mais uma camada de abstração é justificado pelo reuso em outros componentes, módulos e camadas.

Como já descrito acima, quando se trabalha com um ORM, faz sentido criar repositórios para abstrair o código específico do framework. O que não faz muito sentido (já vi isso por aí) é criar DAOs para abstrair o ORM, pois isso é forçar um pouco o conceito de DAO. Repositórios também são bastante úteis para criar implementações alternativas para armazenamento. Como a interface é baseada em coleções, é fácil implementar uma versão do repositório usando uma lista em memória, artifício muito útil para execução de testes unitários ou de integração de forma independente do banco de dados.

Onde eles se parecem

A confusão começa porque tanto DAO quanto Repository abstraem de alguma forma o acesso aos dados, embora, como vimos acima, eles tem níveis completamente diferentes de abstração.

Outro problema é que algumas das operações (métodos) de DAOs e Repositórios são comuns e, dependendo da implementação, não tem diferença alguma. Parte disso é pela implementação incorreta dos padrões. Outra parte é porque nem sempre é possível seguir o modelo em sua completude, por exemplo quando a abstração em forma de uma coleção penaliza o desempenho de tal forma que um repositório precisa implementar um método de mais baixo nível para tornar uma funcionalidade viável.

Onde divergem

Um ponto importantíssimo para entender que a diferença não é apenas acidental é entender a origem dos padrões. Enquanto DAO foi pensado principalmente para abstrair fontes de dados genéricas, o contexto em que Repository foi concebido envolve DDD e pode ser usado com outros padrões específicos.fonte

DAOs podem persistir e recuperar DTOs ou, em sistemas mais simples, das próprias entidades do sistema. Repositórios sempre fazem referência a uma entidade do domínio da aplicação. Claro que você pode estender o conceito para outras coisas, mas não deve ser a norma.

DAOs geralmente abstraem uma query no banco de dados. Repositórios pode necessitar de várias queries para compor uma entidade.

DAOs não gerenciam transações. Repositórios podem gerenciar ou pelo menos exigir a execução dentro de uma transação.

DAOs acessam diretamente a fonte de dados. Repositórios geralmente usam algum outro mecanismo para persistir dados, tal como um ORM ou os próprios DAOs.