O padrão DAO (Data Access Object ou, em pt-BR, Objeto de Acesso a Dados), é uma abstração de persistência de dados e é considerado próximo da camada de armazenamento de dados que, normalmente, é centrado em tabelas.
Entretanto, em muitos casos, o DAO possui muitas tabelas permitindo, de uma forma mais direta, enviar/receber dados do banco, escondendo as queries mais feias.
Exemplo de implementação:
//Primeiramente, criamos a classe de domínio
public class Usuario{
private Long id;
private String nome;
private String email;
//getters e setters
}
//Na sequência, criamos uma interface que provê um CRUD simples para a classe de Domínio do Usuário
public interface UsuarioDao{
void criar(Usuario usuario);
Usuario buscar(Long id);
void atualizar(Usuario usuario);
void deletar(Long id);
}
//Por fim, fazemos a implementação
public class UsuarioDaoImpl implements UsuarioDao{
private final EntityManager em;
@Override
public void criar(Usuario usuario){
em.persist(usuario);
}
@Override
public Usuario buscar(Long id){
return em.find(Usuario.class,id);
}
//...
}
Padrão Repository
De acordo com Eric Evans em seu livro Domain-Driven Design, o "repository é um mecanismo para encapsular o banco, recuperar e buscar comportamento que simulam uma coleção de objetos."
Ainda nessa mesma linha, o livro Padrão de Arquitetura de aplicações Enterprise, do mesmo autor, diz que "entre as camadas de domínio e de mapeamento de dados, utiliza-se uma interface de coleção para acessar os objetos de domínio."
Em outras palavras, o repository também lida com dados e esconde queries de forma semelhante ao padrão DAO. Porém, o repository se trata de uma padrão de alto nível, ou seja, muito mais próximo da lógica de negócio de uma aplicação.
Consequentemente, um repository pode usar um DAO para pegar dados do banco e popular um objeto de domínio, da mesma forma que pode usar um DAO para pegar informações do objeto de domínio e mandar para o armazenamento no banco.
Exemplo de implementação:
public interface UsuarioRepository{
Usuario get(Long id);
void adicionar(Usuario usuario);
void atualizar(Usuario usuario);
void remover(Usuario usuario);
}
public class UsuarioRepositoryImpl implements UsuarioRepository{
//Aqui vamos utilizar o DAO
private UsuarioDaoImpl usuarioDaoImpl;
@Override
public Usuario get(Long id){
return usuarioDaoImpl.buscar(id);
}
@Override
public void adicionar(Usuario usuario){
usuarioDaoImpl.criar(usuario);
}
//...
}
Olhando da forma como fizemos até o momento, ambas implementações parecem muito semelhantes, porque a classe Usuario é uma classe de domínio anêmica. E, o repository, é somente outra camada sobre o DAO.
Entretanto, o DAO se torna um candidato perfeito para acesso aos dados enquanto que o Repository é uma forma ideal de se implementar um UseCase.
Um exemplo mais rico sobre o uso do Repository como UseCase:
public class UsuarioRedeSocial extends Usuario{
private List<Tweet> tweets;
}
public class UsuarioRepositoryImpl implements UsuarioRepository{
//Aqui vamos utilizar o DAO
private UsuarioDaoImpl usuarioDaoImpl;
//Pulamos a etapa de criar o Tweet e TweetDao, mas só para acelerar a compreensão de uma classe de Domínio mais rica
private TweetDaoImpl
@Override
public Usuario get(Long id){
//não queremos mais apenas salvar o usuário, mas queremos o usuário e seus tweets
UsuarioRedeSocial usuario = (UsuarioRedeSocial) usuarioDaoImpl.buscar(id);
List<Tweet> tweets = tweetDaoImpl.fetchTweets(usuario.getEmail());
usuario.setTweets(tweets);
return usuario;
}
@Override
public void adicionar(Usuario usuario){
usuarioDaoImpl.criar(usuario);
}
//...
}
Nesse novo exemplo, temos agregação de informação que provê um objeto de domínio que é útil para o nosso UseCase. O poderíamos fazer o mesmo para as demais redes sociais, no mesmo Repository.
Fonte: DAO vs Repository Pattern
Top comments (1)
Post claro e interessante. Parabéns.