Possibilidades de design no uso do seu Generic DAO
Por Lucas Cavalcanti em 26/07/10Muitas 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 DAOs 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.





Há três meses