Olá ‘javamaníacos’. Tudo bem com vocês?.
Venho aqui pedir a sugestão de vocês quanto a uma arquiterura de Persistencia que desenvolvi para utilizar em meus projetos. Antes de detalhar a estrutura gostaria de discorrer sobre os fatores que me motivaram a construir tal arquitetura. Vou enumerá-las a pertir de agora:
I. Indepedência da camada de persstência
Uma coisa que sempre me atrapalhou bastante e me fez sofrer muita curva de aprendizado foi o fator de ter que escolher um framework ou forma de trabalhar com camada de persistência. Julgar a melhor é uma tarefa árdua quando se trta de ferramentas como JTA, JPA, Hibernate e até mesmo o uso de JDBC puro, que, às vezes, também tem suas vantagens. Então pensei: por que não construir uma arquiteutra que me permita abstrair minha camada de persistência indepedente do framework/metodologia que utilizarei? ou melhor, me permitir que fique livre para usar livremente quaisquer dessa tecnologia., com baixo acoplamento e maior coesão?!
II. Encapsulamento no lugar de Hernça
Agora, que já tenho mais experiência e, na falta de uma expressão melhor. fluência na linguagem, decidi revisar conceitos que deixei passar no início, e um que me chamou bastante atenção foi o princípoio que diz para se dar preferẽncia a encapsulamento e evitar o uso demasiado de Herança . Minha problemática a essa questão era o uso impulsivo de DAOs herdando de um DAO genérico, fazendo com que tivesse várias classes sem nenhuma utilidade maior que uma simples especificação e dezenas de declarações de atributos redundantes em classes Controllers. Me questionei se estava realmente reaproveitando o código ou simplesmente tentando deixar o código mais ‘bonito’.
III. EJB
De todos os motivos este foi o responsável por me despertar aos dois quetionamentos anteriores, o uso de EJB com injeção de depẽdencia me motivou bastante na forma de construir esta arquitetura. Agora, as classes de controle com métodos lotados de linhas ficara bem mais simples com o uso de um SessionBean, que simplificou e muito minha vida
Agora é hora de mostrar esta bendita arquitetura.
Bem para começar aqui está a classe abstrata que decidi criar. Uma classe abstrata declarando os principais métodos de um DAO, comando de persistência simples. Nomei-o de GenericDAOFacade, e já fica aqui uma pergunta, seria essa realmente a denominação certa que deveria utilizar?
public abstract class GenericDAOFacade<T> {
public Class entidade;
public GenericDAOFacade() {
}
public GenericDAOFacade(Class entidade) {
this.entidade = entidade;
}
public abstract void save(T t);
public abstract void update(T t);
public abstract void saveOrUpdate(T t);
public abstract List<T> list();
public abstract T findById(Object id);
public abstract void delete(T t);
public abstract void deleteById(Object id);
public abstract List<T> findByParam(String param, Object value);
public Class getEntidade() {
return entidade;
}
public void setEntidade(Class entidade) {
this.entidade = entidade;
}
}
Bem, acho que vocês devem ter percebido que o único motivo que a torna uma classe abstrata é o fato que ela própria especifica a que Classe, do tipo de Modelo, que uma instância deste DAO será responsável.
Continuando, segue abaixo uma IMplementação de um DAO Genérico, atendendo a minha primeira motivação. Com a classe abstrata fico livre para implementar as diversas formas de um DAO, seja com objeto Session do Hibernate, EntityManger do JPA, usar JDBC ou até mesmo gerenciar minha entidade com coleções. As classes GenricDAOImpl e HibernateGenericDAOImpl exemplificam a justificativa a qual me refiro.
public class GenericDAOImpl<T> extends GenericDAOFacade<T> {
private List<T> lista;
public GenericDAOImpl() {
lista = new ArrayList<T>();
}
public GenericDAOImpl(Class entidade) {
super(entidade);
lista = new ArrayList<T>();
}
@Override
public void save(T object) {
lista.add(object);
}
@Override
public void update(T object) {
lista.indexOf(object);
}
@Override
public List<T> list() {
return lista;
}
@Override
public void delete(T t) {
lista.remove(t);
}
@Override
public T findById(Object id) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void deleteById(Object id) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void saveOrUpdate(T t) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public List<T> findByParam(String param, Object id) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
public class HibernateGenericDAOImpl<T> extends GenericDAOFacade<T> {
private Session session;
public HibernateGenericDAOImpl() {
session = HibernateUtil.getCurrentSession();
}
public HibernateGenericDAOImpl(Class entidade) {
super(entidade);
session = HibernateUtil.openSession();
}
@Override
public void save(T t) {
session.beginTransaction();
session.save(t);
session.getTransaction().commit();
}
@Override
public void update(T t) {
session.beginTransaction();
session.update(t);
session.getTransaction().commit();
}
@Override
public List<T> list() {
return session.createCriteria(entidade).list();
}
@Override
public T findById(Object id) {
return (T) session.createCriteria(entidade).add(Restrictions.eq("id", id)).uniqueResult();
}
@Override
public void delete(T t) {
session.beginTransaction();
session.delete(t);
session.getTransaction().commit();
}
@Override
public void deleteById(Object id) {
T t = findById(id);
session.beginTransaction();
session.delete(t);
session.getTransaction().commit();
}
@Override
public void saveOrUpdate(T t) {
session.beginTransaction();
session.saveOrUpdate(t);
session.getTransaction().commit();
}
@Override
public List<T> findByParam(String param, Object value) {
return session.createCriteria(entidade).add(Restrictions.eq(param, value)).list();
}
}
Bem, agora valendo-se da minha terceira motivação, segue abaixo o que considero o grande manda-chuva da arquitetura. A classe DAOFactory. Será ela um Stateless SessionBean que porverá instâncias de DAOs a minha aplicação abtraindo a metodologia que é utilizada. É ele que devolve uma instância de DAO válida para as classes de controle ou de negócio de uma forma transaparente, sem denotar qual tipo de persistância está sendo utilizada.
@Stateless
public class DaoFactory {
private GenericDAOFacade genericDAO;
public String teste(){
return "teste";
}
public GenericDAOFacade getGenericDAO(Class clazz) {
try {
genericDAO = (GenericDAOFacade) Class.forName(ContantesAplicacaoUtil.GENERIC_DAO_CLASS).newInstance();
genericDAO.setEntidade(clazz);
} catch (InstantiationException ex) {
Logger.getLogger(DaoFactory.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(DaoFactory.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(DaoFactory.class.getName()).log(Level.SEVERE, null, ex);
}
return genericDAO;
}
}
E por fim, um exemplo para justificar o uso de EJB e uso de encapsulamento no lugar de Herança.
public class EmpresaManager {
@Inject
private DaoFactory daoFactory;
public EmpresaManager() {
}
public EmpresaManager(DaoFactory daoFactory) {
this.daoFactory = daoFactory;
}
public void cadastrarEmpresa(Empresa empresa) {
empresa.setSenha(FacesUtils.md5(empresa.getSenha()));
daoFactory.getGenericDAO(Empresa.class).saveOrUpdate(empresa);
}
public void cadastrarConta(Conta conta, Empresa empresa) {
conta.setEmpresa(empresa);
daoFactory.getGenericDAO(Conta.class).save(conta);
}
public List<Conta> buscarContaPorEmpresa(Empresa empresa){
return daoFactory.getGenericDAO(Conta.class).findByParam("empresa", empresa);
}
public DaoFactory getDaoFactory() {
return daoFactory;
}
public void setDaoFactory(DaoFactory daoFactory) {
this.daoFactory = daoFactory;
}
}
Isto seria um exemplo de uma classe de negócios com métodos bem específico ao caso de uso de um cadastro Empresa que posssui várias contas. Note duas coisas.
- O uso do DAOFactory para prover as instâncias de DAO necessárias, me dispensando a construção DAOs específicos e declaração de vários objetos que são idênticos e com a mesma funcionalidade.
- O uso de herança dispensado, aqui trat-se apenas dmétodos específicos. Minha dúvida é: Isso caracteriza ou não um BO?
Enfim, no fundo, quis compartilhar um pouco da minha visão sobre tal arquietura e pedir a opnião de vocês quanto ás duvidas levantadas e sobre qualquer outra coisa que vocês possam agregar a meu conceito. Desde já grato pela atenção.