Eu uso o design pattern DAO com a estratégia de fábrica abstrata desde que me entendo por gente.
Fiz a seguinte modificação na implementação demonstrada no catálogo de padrões J2EE:
- Inicializar o objeto de conexão, com o repositório de dados, na inicialização da fábrica concreta.
- Passar o objeto de conexão, com o repositório, pelo construtor das implementações(deste repositório) das interfaces DAOs.
- Deslocar para o usuário, do DAO, a responsabilidade de criar e terminar uma transação ao executar seus métodos. Isto é feito à partir da DAOFactory, que possui métodos para controle transacional dos DAOs criados por ela.
Tenho usado essa implementação sem problemas há, aproximadamente, 2 anos.
Mas considero insuportável escrever os métodos abstratos(na fábrica abstrata) para retornar a implementação do DAO e ainda ter que escrever a implementação destes métodos em cada fábrica concreta. Implementação esta que consiste apenas em dar um new em uma classe e colocar o objeto de conexão com o repositório no construtor.
Neste feriado, eu resolvi dar um fim nesses métodos.
O desafio era fazer isso sem perder a checagem feita pelo compilador se a classe DAO que eu estou retornando implementa a interface DAO que eu estou querendo usar.
E para isso comecei definindo algumas convenções:
- O nome da interface DAO será o nome da entidade com o sufixo DAO. Por exemplo, o DAO para a entidade Cliente será ClienteDAO;
- O pacote, onde ficam as interfaces e a fábrica abstrata será assim: pacote.do.sistema.dao;
- O nome da implementação da interface DAO será o nome da interface DAO com o prefixo do repositório. Por exemplo, a implementação usando JPA será: JpaClienteDAO;
- O pacote, onde ficam a implementação e a fábrica concreta, será um sub-pacote, do pacote onde estão as interfaces e a fábrica abstrata, como em: pacote.do.sistema.dao.jpa;
Essas convenções me permitiram modificar a fábrica abstrata para retornar a implementação de uma interface DAO a partir da interface DAO.
Esta “mágica” é feita pelo método getDao:
public <T extends CrudDAO> T getDao(Class<T> daoInterface) thrws DAOException{ |
Mas ainda preciso saber o prefixo das implementações. Para resolver isso criei um método, na fábrica abstrata, que retorna uma String. Esta String é o prefixo da implementação, que a fábrica concreta, irá informar.
Na fábrica abstrata, isto é, a classe DAOFactory:
protected abstract String getPrefixoImpl(); |
E a implementação na fábrica concreta usando a JPA, isto é, JpaDAOFactory:
@Override return "jpa"; |
Eu tenho uma classe base para os meus DAOs, que implementam as operações básicas de inclusão, alteração, exclusão e busca da entidade, e tem um contrutor que recebe o EntityManager a ser usado nestas operações.
Por conta deste contrutor eu preciso dos métodos getRepositoryTypes() e o getRepositoryArgs que irão retornar o objeto responsável pelo acesso ao banco de dados(EntityManager no caso do JPA, Session no caso de Hibernate e Connection no caso de JDBC “cru”).
Com essas alterações simples eu posso recuperar a implementação do DAO sem precisar criar um método para cada DAO em cada implementação da fábrica abstrata.
E para usar a nova implementação, o código fica assim:
DAOFactory factory = DAOFactory.getInstance();
EntidadeDAO dao = factory.getDao(EntidadeDAO.class);
Faça o download do projeto, para Eclipse, que tem a implementação de tudo o que eu escrevi até aqui.
Por restrições do WordPress eu tive que renomear a extensão do arquivo para “pdf”, basta trocar por “zip” que você irá conseguir descompactá-lo.
Para usá-lo:
- Importe o projeto para o seu eclipse;
- Coloque o driver para o banco de dados e adicione-o ao class-path do projeto;
- Configure o arquivo persistence.xml na pasta META-INF com os dados da conexão ao seu banco;
- Execute a classe ExemploMain.
Sugestões serão bem vindas. E analisadas, caso eu concorde coloco no exemplo e atualizo ele.
Po-por hoje é só pe-pe-ssoal. =D
Opa,
estou implementando a sua fabrica abstrada de JPA (que por sinal é muito interessante), e seugui uma duvida.
quado eum precisar fazer um query (por named query). o que eu fiz, foi:
1- crigar um get/setter do manager na classe JpaBaseDAO.
depois na minha classe entity onde estão as @NamedQuety criei o metodo
@SuppressWarnings(“unchecked”)
public static List findByGui(Integer oid){
JpaDAOFactory factory = (JpaDAOFactory) DAOFactory.getInstance(DAOFactory.JPA);
Query q = factory.getManager().createNamedQuery (“selectWhereGui”);
q.setParameter (“gui”, oid);
return q.getResultList();
}
o que voce acha dessa abordagem?
1. Não precisa dos métodos get e set para o EntityManager, porque ele pode ser acessado diretamente no DAO. O nome do atributo é manager.
2. na sua entidade você pode continuar usando:
public static List findByGui(Integer oid){
DAOFactory factory = DAOFactory.getInstance();
SuaEntidadeDAO dao = factory.getDao(SuaEntidadeDAO.class);
return dao.findByGui(oid);
}
E no DAO, você usa a NamedQuery:
public List findByGui(oid){
Query query = manager.createNamedQuery(“selectWhereGui”);
q.setParameter (”gui”, oid);
return q.getResultList();
}
[],
AC
[...] o embasamento deste post refere-se ao Blog do Beyond e no artigo do Davi Lucas no [...]
O que você acha desse DAO genérico (ñ usa anotações) com integração com o Hibernate?
http://www.nabble.com/Re:-D%C3%BAvidas-sobre-JPA-p15185421.html
O que me incomodou no seu exemplo é o controle de transação ser feito pelo DAO. Por exemplo se uma transação envolver mais de um DAO, em qual deles eu mando fechar a transação? Entendo que em qualquer um serve, mas não fica claro isso no código.
Nos métodos findById e findAll, você está passando o Class. Uma vez que os DAOs possuem uma implementação, poderia usar a idéia de TemplateMethod e criar um método protected abstrato que retornasse o Class.
Gostei muito do uso da API de Criteria e do método de paginação. Inclusive devo fazer um update do meu exemplo usando a mesma idéia. :)
Velho, que código bem escrito!! Nossa, de fundamento o seu projeto. Usarei ele para me basear em meus estudos. Obrigado.