Ainda hoje vejo muita gente utilizando o padrão DAO em novos projetos, mesmo usando novas tecnologias de persistência como Hibernate e JPA. Não vou entrar em discussões sobre o padrão DAO estar morto ou não. O fato é que em projetos legados, principalmente os que usam JDBC, o DAO está bem vivo. Mas e em projetos que usam ORM? É necessário usar DAOs e os famosos DAOs Genéricos?
Usar DAOs, hoje, pode ser algo extremamente redundante. Pois as ferramentas de ORM já implementam o padrão DAO. Por que você implementaria novamente? Mas, claro, mesmo em projetos novos, pode ser que apareça o cenário para se utilizar o DAO. É uma decisão de design que não deve se basear em senso comum. Projetar software não é uma tarefa trivial, porém, muitos ainda se baseiam em receitas de bolo e não param para trabalhar no design da aplicação. Mas nós aprendemos a criar DAOs na camada de persistência. Como fazer de outra maneira?
Lembre-se que o DAO existe para abstrair a camada de persistência e criar uma interface para o acesso aos dados. Hoje isso já está pronto e quem o faz é a ferramenta de ORM. Em determinados cenários não vejo problema em injetar o EntityManager do JPA direto no Controller. Algumas vezes não existe motivo para se criar uma camada desnecessária. No entanto, é mais usual que tenhamos que fazer consultas usando HQL ou JPA QL, ou que seja necessário o controle manual de transações. Esse tipo de coisa jamais deve ficar na camada de aplicação. Existe uma forma mais elegante de abstrair a camada de persistência. Criando repositórios.
Repository é um conceito do Domain Drive Design. A camada de domínio de uma aplicação é onde se encontram as regras de negócio, logo, o que ocorre nessa camada está na \\\’boca do povo\\\’, ou seja, está nos brainstorms, reuniões de levantamento de requisitos, e nas conversas entre desenvolvedores e pessoal de negócios. A camada de domínio precisa ser escrita no que chamamos de linguagem ubíquoa, a linguagem comum entre devs e negócios.
O que normalmente encontramos dentro de controllers é algo assim:
[code language=\\\”java\\\”]
BookDao dao = new BookDAO();
Book book = dao.findById(id);
[/code]
Primeiro, se estivermos usando ORM, o DAO é desnecessário. Segundo, é feio de ler. Não tem nada a ver com uma liguagem de domínio. É muito comum as pessoas somente trocarem o nome DAO por Repository e modificar a interface método.
[code language=\\\”java\\\”]
/**
*/
public class BookRepository {
public final EntityManager entityManager;
public BookRepository(EntityManager entityManager){
this.entityManager = entityManager;
}
public void add(Book book){
this.entityManager.merge(book);
}
public Book findBook(String id){
return this.entityManager.find(Book.class, id);
}
}
[/code]
A chamada fica assim:
[code language=\\\”java\\\”]
BookRepository bookRepository = new BookRepository();
Book book = bookRepository.findBook(id);
[/code]
Bem melhor, mas ainda temos alguns problemas. Muitos desenvolvedores costumam usar o termo repository no nome das classes, assim como fazem com o dao. Devemos usar nomes significativos para nossas classes, métodos e variáveis, principalmente em se tratando de classes de domínio. Que tal se mudarmos o nome da nossa classe para Library?
[code language=\\\”java\\\”]
Library library = new Library();
Book book = library.findBook(id);
[/code]
Uma coleção de livros, geralmente é uma biblioteca, não é verdade? Mas ainda há um problema. O alto acoplamento com a implementação do repositório. Em se tratando de uma classe de repositório, ela poderá ser usada em vários locais, tanto em controllers, quanto em classes de serviços e até mesmo por classes de modelo. Mesmo usando injeção de dependência, ainda ficamos acoplados com a camada de persistência. Então podemos criar uma interface.
[code language=\\\”java\\\”]
public interface Library{
void add(Book book);
List<Book> allBooks();
Book findBook(String id);
}
[/code]
E fazemos com que a classe repository implemente a interface Library.
[code language=\\\”java\\\”]
public class BookRepository implements Library {
public final EntityManager entityManager;
public BookRepository(EntityManager entityManager){
this.entityManager = entityManager;
}
public void add(Book book){
this.entityManager.merge(book);
}
public List<Book> allBooks(){
return this.entityManager.createQuery("select b from Book b", Book.class).getResultList();
}
public Book findBook(String id){
return this.entityManager.find(Book.class, id);
}
}
[/code]
Agora através de injeção de dependência, as classes podem receber a interface Library como dependência, e não mais depender de sua implementação. Podemos criar uma camada de persistência e inserir as classes *Repository nela enquanto que as interfaces ficam na camada de domínio. Em Domain Drive Design, as classes que implementam a persistência localizam-se na camada de infraestrutura enquanto que as interfaces dos repositórios podem ficar no mesmo pacote dos modelos, na camada de domínio.
Deixe um comentário