O que vocês acham deste modelo de Arquitetura?

Olá galera, li um tópico do GUJ sobre dao’s nas classes de negocio, e sobre o pattern repository, mas alguma coisas ainda não ficaram claras, então resolvi postar o meu modelo de arquitetura para ver o que vocês acham.

Ele está definido da seguinte forma

WEB > Action > DAO > Implementacao DAO > Banco

Segue o modelo dos DAO’s

public interface Dao <T> {

	public T get(Serializable id) throws DAOException;	
	public void save(T entidade) throws SaveException;
	public T update(T entidade) throws UpdateException;
	public void delete(Serializable id) throws DeleteException;
	public List<T> findAll() throws QueryException;
	public List<T> findAll(final Integer primeiro, final Integer maxino) throws QueryException;
}

AbstractDao

@SuppressWarnings("unchecked")
public abstract class AbstractDao<T> implements Dao<T>{

		
	private EntityManager em;
	private Map<String, Object> parametros = new HashMap<String,Object>();
 	private String declaracao;
 	
 	 	
 	public AbstractDao(){
		em = JPAFilter.getEm();  //Filtro Global de controle de transaction, invocado pelo Mentawai
	}
 	
 	 	
	public final EntityManager getEm() {
		return em;
	}
	public void setEm(EntityManager em) {
		this.em = em;
	}
	
	
	protected abstract Class<T> getDefineClass() ;

	
	public T get(Serializable id) throws DAOException{
		try{
			T entidade = (T) getEm().find(getDefineClass(), id);
			return entidade;
		}catch (Exception e) {
			throw new DAOException(e.getMessage());
		}		
	}

	public void save(T entidade) throws SaveException {
		try{
			getEm().persist(entidade);
		//	getEm().flush();
		}catch (Exception e) {
			throw new SaveException(e.getMessage());
		}
	}
		
	public T update(T entidade) throws UpdateException {
		try{
			if(entidade == null){
				throw new SaveException("Objeto nulo para update");
			}
			preUpdate(entidade);
			return getEm().merge(entidade);
		}catch (Exception e) {
			throw new UpdateException(e.getMessage());
		}		
	}
	
	public void delete(Serializable id) throws DeleteException {
		try{
			if(id == null){
				throw new DeleteException("Objeto nulo para dele&ccedil;&atilde;o");
			}
			getEm().remove(get(id));
		}catch (Exception e) {
			throw new DeleteException(e.getMessage());
		}		
	}
  
    protected final void addParametros(String key, Object value) {
    	parametros.put(key, value);
    }
    
    protected final void addParametros(Integer key, Object value) {
    	addParametros(String.valueOf(key), value);
    }
    
    protected final void limpaParametros() {
    	parametros.clear();
    }
    
    protected final void setDeclaracao(String declaracao) {
    	this.declaracao = "FROM "+getDefineClass().getName()+" "+declaracao;
    }
    
    public List<T> findAll() throws QueryException {
    	try{
        	setDeclaracao("");
        	return find();
    	}catch (Exception e) {
			throw new QueryException(e.getMessage());
		}
    }
    
    public List<T> findAll(Integer primeiro, Integer maximo) throws QueryException {
    	try{
    		setDeclaracao("");
        	return find(primeiro, maximo);
    	}catch (Exception e) {
			throw new QueryException(e.getMessage());
		}    	
    }
    
    protected List<T> find() throws QueryException {
		try{
			return find(0, 0);
		}catch (Exception e) {
			throw new QueryException(e.getMessage());
		}
    }
    
    protected List<T> find(Integer primeiro, Integer maximo) throws QueryException {
		try{
			Query query = getEm().createQuery(declaracao);
			addParamQuery(query);
			List result = null;
	        try {
	        	if(primeiro != 0){
	        		query.setFirstResult(primeiro);
	        	}
	        	if(maximo != 0){
	        		query.setMaxResults(maximo);
	        	}
	        	
	        	result = query.getResultList();
	        	
	        	if (result.isEmpty()) {
	        		throw new Exception();
	        	}
	        } catch (Exception e) {
	        	throw new QueryException("Nenhuma informacao encontrada!");      	
	        }
	       return result;
		}catch (Exception e) {
			throw new QueryException(e.getMessage());
		}
    }
    
    private void addParamQuery(Query query) throws QueryException {
    	try{
    		for (Iterator it = parametros.entrySet().iterator();it.hasNext();) {
        		Entry entry = (Entry) it.next();
        		try {
        			query.setParameter(Integer.parseInt((String) entry.getKey()),entry.getValue());
        		} catch (NumberFormatException e) {
        		    query.setParameter((String) entry.getKey(), entry.getValue());
        		} catch (Exception e1) {
        			throw new QueryException(e1.getMessage());
        		}
        	}
        	parametros.clear();
    	}catch (Exception e) {
			throw new QueryException(e.getMessage());
		}    	
    }
    
    public Long selectCount() throws QueryException{
    	try{
    		Long count = -1L;
        	try{
        		Query query = getEm().createQuery("SELECT COUNT(*) "+declaracao);
        		count = (Long) query.getSingleResult();
        	}catch (Exception e) {
    			throw new QueryException(e.getMessage());
    		}
        	return count;
    	}catch (Exception e) {
			throw new QueryException(e.getMessage());
		}    	
    }
    
    public List<T> findByExample(T example) throws QueryException {
    	return findByExample(example, 0, 0);
    }
    
	public List<T> findByExample(T example, Integer primeiro, Integer maximo) throws QueryException {
    	final Session session = (Session) getEm().getDelegate();
    	final Criteria c = session.createCriteria(getDefineClass());
    	Example e = Example.create(example).enableLike(MatchMode.ANYWHERE);
    	c.add(e);            
    	addOrderToCriteria(c);
    	if(primeiro != 0){
    		c.setFirstResult(primeiro);
    	}
    	if(maximo != 0){
    		c.setMaxResults(maximo);
    	}
    	return c.list();
    }
    
	public T findOneByExample(T example) throws QueryException {
		final List<T> result = findByExample(example, 0, 1);
		if(result != null && !result.isEmpty()){
			return result.get(0);
		}else{
			return null;
		}
	}
	
	public Integer selectCountByExample(T example) throws QueryException {
		try{
    		Integer count = -1;
        	try{
        		count = findByExample(example).size();
        	}catch (Exception e) {
    			throw new QueryException(e.getMessage());
    		}
        	return count;
    	}catch (Exception e) {
			throw new QueryException(e.getMessage());
		}
	}
	
	public Session getSession() {
		return (Session) getEm().getDelegate();
	}
	
    protected void preUpdate(T entidade) throws UpdateException {}	
	protected void addOrderToCriteria(Criteria criteria){}
    
}

Ai por exemplo quando eu vou criar um UsuarioDAO , eu crio uma interface UsuarioDAO deste jeito:

public interface UsuarioDao extends Dao<Usuario> {
	
	public Usuario getPorLogin(String login) throws QueryException;

}

Ai tenho a implementação do DAO definida assim:

public class UsuarioDaoImpl extends AbstractDao<Usuario> implements UsuarioDao {

	protected Class<Usuario> getDefineClass() {
		return Usuario.class;
	}

	public Usuario getPorLogin(String login) throws QueryException {
		setDeclaracao("where login=?");
		addParametros(1, login);
		return find().iterator().next();
	}

}

A action abstrata fica definida assim:

@SuppressWarnings("unchecked")
public abstract class AbstractAction <T> extends BaseAction  {	
	private static final Logger log = Logger.getLogger(AbstractAction.class);
	private T bean = null;
			
	public T getBean() {
		return bean;
	}
	public void setBean(T bean) {
		this.bean = bean;
	}

       protected abstract Dao<T> getDao(); 
    .....

Ai quando quero criar uma action herdo de AbstractAction, e reescrevo o método abstrato getDao, que retorna o dao correspondente que minha action tem como atributo, injetado via IOC.

Ex:

public class UsuarioAction extends AbstractAction<AbstractUser> {

	private UsuarioDao usuarioDao;  //Populado via filtro global de IOC
	
	protected Dao<AbstractUser> getDao() {
		return usuarioDao;
	}
}

O que acham deste modelo, gostaria de opiniões sobre como posso melhorar, dicas sugestões, etc…

Grato

com relação a arquitetura (pacotes, classes, dependencia) está bem definido. Basta saber se ela atende a todas as suas necessidades. (Aberto para extensões e fechado para modificações)

Dao dentro de Action? :roll:, Faz o Action acessar uma camada de serviço, que contenha REPOSITÓRIOS (que são implementações de DAOS)!

O problema que encontramos aqui é o seguinte: Será que realmente é necessário criar esse camada Service? Não seria apenas mais uma camada, que apenas legaria as funcionalidades para o dao?

Na verdade o DAO é que pode ser uma implemtação de um repositorio…

O seu sistema é um CRUD simples
Onde vão estar suas regras de negocio? nas actions? nos DAOs?

A camada de serviço nessa sua arquitetura podeira servir p/ conter as RN, nao ser so um delegate p/ DAOs.

[]´s

[quote=jgbt]Na verdade o DAO é que pode ser uma implemtação de um repositorio…

O seu sistema é um CRUD simples
Onde vão estar suas regras de negocio? nas actions? nos DAOs?

A camada de serviço nessa sua arquitetura podeira servir p/ conter as RN, nao ser so um delegate p/ DAOs.

[]´s

[/quote]

Olá João, o sistema não é um CRUD simples, as regras de negócio estão no model, já teve essa discussão aqui no guj neste tópico http://www.guj.com.br/posts/list/60916.java o que eu fiquei sem entender é o seguinte a inves da minha Action acessar diretamente um Dao ela acessaria esse repositorio desse jeito:

Web> Action > Modelo de Negocios > Dao > ImplemtacaoDao > Banco

Modelo de negocios aqui seria o repositorio de acordo com o pcalcado repository==Modelo de Negocios.

Agora o que eu não entendi foi o seguinte , de acordo com o que o foi dito nos posts que coloquei um repository é uma interface, então como teria regras de negócio nela, sendo que ela é uma interface e não tem nenhuma implementação??

Pelo que acompanho as threads a sua RN deve estar na Entidade.

O Repository é responsavel em persistir/salvar os dados bd/xml/file.
Por isso o Repository pode ser um DAO.

Espero ter ajudado… :slight_smile:

Bom, não tinha entendido que vc queria usar DDD.
Acho que vc esta confundindo algumas coisas. Repositorio não “é” o modelo de nogocios, ele faz parte do modelo. As regras de negocio devem estar nas entidades de negocio que vc identificou. Essas entidades acessam um repositorio para guardar/recuperar estado. Esse repositorio pod ser um DAO. Sua action ate poderia acessar os entitys, mas o ideal seria acessar uma camada de servico. Essa camada se precisar, pode usar N entitys para realizar alguma operação, dependendo da necessidade.

[]'s

Keller, de acordo com esta definição feita pelo CV

Então acho que é o contrário não Dao implements Repository

Estou errado??

Valeu!

[quote=danielbussade]Keller, de acordo com esta definição feita pelo CV

Então acho que é o contrário não Dao implements Repository

Estou errado??

Valeu![/quote]

Mas nao foi isso que eu disse ? :lol:

Um Repository pode ser um DAO.
Então: public class EntidadeDAO implements EntidadeRepository{ }

Como também pode ser alguma outra classe que salve os dados em XML/File/XYZ.
Então: public EntidadeXML implements EntidadeRepository{ }

E os Repository’s podem ser utilizados da Entidade.
E como o CV ja disse preferencialmente via DI. ( Dependency Injection )

Espero ter sido mais claro agora. :slight_smile:

Tente evitar herança só para ganhar métodos. Se não vai usar polimorfismo prefira composição!

[quote=jgbt][quote=danielbussade]
Olá João, o sistema não é um CRUD simples, as regras de negócio estão no model, já teve essa discussão aqui no guj neste tópico http://www.guj.com.br/posts/list/60916.java o que eu fiquei sem entender é o seguinte a inves da minha Action acessar diretamente um Dao ela acessaria esse repositorio desse jeito:

Web> Action > Modelo de Negocios > Dao > ImplemtacaoDao > Banco

Modelo de negocios aqui seria o repositorio de acordo com o pcalcado repository==Modelo de Negocios.

Agora o que eu não entendi foi o seguinte , de acordo com o que o foi dito nos posts que coloquei um repository é uma interface, então como teria regras de negócio nela, sendo que ela é uma interface e não tem nenhuma implementação??
[/quote]

Bom, não tinha entendido que vc queria usar DDD.
Acho que vc esta confundindo algumas coisas. Repositorio não "é" o modelo de nogocios, ele faz parte do modelo. As regras de negocio devem estar nas entidades de negocio que vc identificou. Essas entidades acessam um repositorio para guardar/recuperar estado. Esse repositorio pod ser um DAO. Sua action ate poderia acessar os entitys, mas o ideal seria acessar uma camada de servico. Essa camada se precisar, pode usar N entitys para realizar alguma operação, dependendo da necessidade.

[]'s[/quote]

Olá João reposiórios fazem parte do modelo de negócios foi isso que quer dizer, uma coisa que estou com dúvida é o usando o DDD ficaria assim ???

Web&gt; Action &gt; DomainModel(negocio propriamente dito) &gt; Repository &gt;ImplementacaoRepository(Nao necessarimante um DAO) &gt; Banco 

Agora é se o repository não fosse um Dao, eu implementaria ele com o que???

Outra coisa que acho estranho neste modelo é a propria entidade se salvar? O que vocês acham ??

Grato

Daniel, não é bem assim, não existe essa separação entre Domain Model e Repository. Repository também faz parte do domínio.

E eu também não sou muito a favor de interfacear tudo sem muita justificativa. Se você não vai ficar mudando de ORM (o que geralmente é o caso), não vejo muita necessidade desse RepositoryImpl, enche o saco na hora de ficar adicionando métodos, tem que ficar lembrando de colocar na interface e tudo mais. Enfim, é uma burocracia que eu particularmente não vejo nenhum benefício. Sem alguém vê algum benefício e puder apontar para mim eu agradeço.

Sobre a entidade se salvar, pesquise por ActiveRecord. Muitos torcem o nariz para ele, outros gostam (e.g. Eu). Vai do gosto de cada um.

Boa sorte aí!

[quote=danielbussade]Olá galera, li um tópico do GUJ sobre dao’s nas classes de negocio, e sobre o pattern repository, mas alguma coisas ainda não ficaram claras, então resolvi postar o meu modelo de arquitetura para ver o que vocês acham.


[/quote]

  1. Use um encadeamento de exceções decente.
  2. Se você precisa de @SuppressWarnings(“unchecked”), ainda mais com escopo de classe, é porque você está fazendo algo errado.
  3. Nos métodos selectCount() e find(Integer, Integer) de AbstractDao você não precisa ter dois try’s aninhados.
  4. No método addParamQuery(Query) de AbstractDao use o enhanced-for.
  5. catch (Exception e) é coisa de programador preguiçoso:

Desculpe mas voce entendeu errado. Repositório (que NÃO é DAO) faz parte do modelo de negócios mas ele não É o modelo de negócios e além do que dificilmtente temregras de negócio em si. Regras de negócio ficam em objetos de negócio.

Se você quer usar Domain-Driven Design eu recomendo que leia o livro antes. em se expôr à metodologia você vai apenas entulhar patterns sem sentido, Você pode entender os conceitos sem ler o livro mas isso fica muito difícil, além de diversas pessoas estarem postando conceitos sobre DDD que não correspondem ao que é difundido por Eric Evans -basta ler em qualquer thread sobre DDD aqui como as pessoas falam do que não entendem.

Olá obrigado a todos pelas respostas, quanto ao DDD, philip você poderia me indicar algum livro em português que falasse sobre ele??
Pafuncio, vou procurar sobre ActiveRecord, agora entendi que o repository e o negocio fazem parte de uma camada só.

Pafuncio, tbm, não gosto de interfacear tudo, pra mim é abstração d+ sem sentido, mas como você mesmo disse se tiver alguém aqui que saiba dizer qual é a vantagem eu tbm agradeço.

Valeu

Vc leu que era uma interface e acreditou. E não se deu ao trabalho de pesquisar o padrão repository ?

http://martinfowler.com/eaaCatalog/repository.html
http://sergiotaborda.wordpress.com/java/patterns/repository/

E ai , acha mesmo que Repository pode ser uma interface ?
E já agora, acha mesmo que pode ser um DAO ?

A estrutura mais correta é a seguinte

Web > Action > Factory > Façade / Service > Model > Repository > DAO > ImplementaçãoDAO > Banco
Num save ou em algum comando de processo e

Web < Action < Façade/Repository < DAO < ImplementaçãoDAO < Banco
Num processo de pesquisa/listagem/report

Até onde eu sei não existe livro em português. Você pode baixar uma versão resumida do livro, em Ingles, no infoQ. E muito cuidado com quem diz o que é “correto” ou não, muita ente aqui e em outros lugars vende verdades absolutas que não condizem com a realidade, ma busca aqui no fórum mostra vários casos.

Obrigado philip e sérgio pelas dicas, realmente é difícil acreditar em tudo que se lê no forum, vou procurar algum material sobre o padrão, que me interessei bastante.

Valeu