Artigos

Criando abstrações com repositórios

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.

Baixe aqui, um exemplo de aplicação modelada com DDD.

Um comentário

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *