Possibilidades de design no uso do seu Generic DAO

Possibilidades de design no uso do seu Generic DAO
lucas
lucas

Compartilhe

Muitas vezes, quando estamos criando nosso sistema temos a tentação de criar o GenericDAO para não ter que ficar repetindo as operações CRUD e listagens.

O maior problema com o GenericDAO é que não necessariamente todas as operações fazem sentido para uma determinada classe. Daí o que fazer se, por exemplo, não faz sentido excluir um pagamento?

 public class PagamentoDAO extends GenericDAO<Pagamento> { @Override public void excluir(Pagamento pagamento) { throw new UnsupportedOperationException(); } } 

Não parece uma solução muito elegante, mas é um dos únicos jeitos de proibir uma operação declarada na classe mãe, e ainda assim, só funciona em tempo de execução. Esse é um dos principais motivos para muitos não gostarem de usar o GenericDAO e preferirem usar composição ao invés de herança. Mas como fazer para não repetir o código trivial das operações do CRUD?

Um dos jeitos é usar uma outra abstração de persistência de objetos: o Repository. Com o Repository, temos um lugar onde podemos guardar e buscar por objetos, não importando como fazemos isso. O DAO já está muito ligado com armazenamento em banco de dados, e foi criado quando as operações do BD eram muito trabalhosas (em especial no JDBC).

E como juntar o Repository com o GenericDAO? O Repository pode ser definido, por exemplo, como uma interface, e aí podemos fazer o seguinte: se, para um pagamento, faz sentido apenas salvar e listar, mas não excluir, então criamos a interface:

 public interface PagamentoRepository { void salva(Pagamento pagamento); Pagamento busca(Long id); List<Pagamento> lista(); } 

E usamos o GenericDAO como implementação dessa interface:

 class PagamentoDAO extends GenericDAO<Pagamento> implements PagamentoRepository { // implementacao extra } 

E no nosso código de domínio "nunca" referenciaremos o PagamentoDAO, apenas o PagamentoRepository, assim mesmo que a implementação saiba fazer mais coisas, a interface só expõe as operações suportadas.

Se você usa Injeção de Dependências e algum framework que a suporta (como o VRaptor, Spring ou Java EE6), você pode deixar os _DAO_s apenas como infraestrutura, e usar os Repositories como interfaces públicas da sua aplicação:

 public class PagamentoController { public PagamentoController(PagamentoRepository repository) { this.repository = repository; }

public void salva(Pagamento pagamento) { // validações e outras regras repository.salva(pagamento); } } 

Ainda poderíamos melhorar o nome do nosso repositório para BaseDePagamentos, ContasAPagar ou ainda Pagamentos, evitando usar sufixos nas classes. Usando abstrações e padrões simples conseguimos evitar repetição de código sem perder a semântica e restrições das nossas classes de modelo, além de esconder detalhes de implementação.

Veja outros artigos sobre Programação