Duvida sobre violação de Camadas + J2EE

Olá pesoal,relendo artigo da Revista Mundo Java, de 2006(meio antigo eu sei) sobre Arquitetura em Camadas, que basicamente existem quatro camadas:

.Apresentação
.Aplicação
.Negocios
.Peristencia

Considerando, que uma Action/Servlet, faz parte da camada de apresentação, como visto em no artigo
http://www.fragmental.com.br/wiki/index.php?title=MVC_e_Camadas então se eu chamar um Dao, seja por composition ou intanciando dentro de um metodo estaria violando uma camada correto?

Pois estou chamando Apresentacao -> Persistencia diretamente, então para resolver isso o que poderia fazer ?

1- Criar um repositorio(que faz parte da camada de negocio) e a action/servlet chamar o repositorio
2-Cria um Façade GerenciadorUsuario e nele expor o metodo criarUsuario(parametro), dentro delete invocar o Dao
mas aqui ainda estaria violando, pois nao passei pela camda de negocios.

3- Criar um metodo save dentro De Usuario(ActiveRecord), e minha action/servlet chamar Usuario.save(usuario);

Ou seja é uma boa prática sempre a camada de negocios acesar a camada de Persistencia

Uma outra dúvida, no mesmo artigo diz que MVC é padrão para camada de apresentação, e que dificilmente será aplicado em outros lugares. seguindo este principio, dividindo o MVC, o único que não seria da camada de apresentação é o Model, que artigo diz que e a interface para objetos de negocio?

O que seria essa interface?

Obrigado!

Eric Evans fala em seu livro Domain Driven Design que a camada de aplicação pode sim acessar serviços da camada de infraestrutura, onde persistência é apenas um dos serviços fornecidos pela mesma.

Aqui tem uma imagem do diagrama do livro:
http://www.elbandit.co.uk/images/JimmyDDD.jpg

Trecho extraído do livro Domain Driven Design Quickly:

Não era necessário uma justificativa tão rigorosa para fazer o que você quer fazer, mas uma vez que foi solicitada, aí está.

[quote=tnaires]Trecho extraído do livro Domain Driven Design Quickly:

Não era necessário uma justificativa tão rigorosa para fazer o que você quer fazer, mas uma vez que foi solicitada, aí está.[/quote]

Olá tnaires, mas neste exemplo ele fala sobre ApplicationLayer, o que subtende por Façades, BussinesDelegate ,etc…

Mas no meu caso estou falando de Servlet/Action, que são da Camada de Apresentação, e não da Camada de Aplicação, por isso perguntei se seria uma violação de camada.

O que gostaria de saber é se eu tivesse uma estrutura do tipo

Web->Action -> Persistencia -> SGDB

Seria uma violação de camada?

Valeu

Putz… Foi mal, li apresentação e entendi aplicação…

Nesse caso, segundo o DDD, teoricamente não seria adequado. Mas pense em duas coisas:

  1. Um sistema que segue o padrão Layered Architecture do DDD deve ter necessariamente uma camada de aplicação, de onde você acessaria a infraestrutura conforme acima. Mas você deve se questionar para quê serve a camada de aplicação e se você precisa dela de fato. Se você chegar à conclusão de que não precisa, o jeito é você acessar a infraestrutura diretamente da camada de apresentação - leia-se, actions/managed beans;
  2. Veja que no diagrama do livro há também uma conexão entre as camadas de apresentação e infraestrutura.

Resumidamente, se você precisa de uma camada de aplicação, não faz sentido acessar a infraestrutura a partir da apresentação.

[quote=tnaires]Putz… Foi mal, li apresentação e entendi aplicação…

Nesse caso, segundo o DDD, teoricamente não seria adequado. Mas pense em duas coisas:

  1. Um sistema que segue o padrão Layered Architecture do DDD deve ter necessariamente uma camada de aplicação, de onde você acessaria a infraestrutura conforme acima. Mas você deve se questionar para quê serve a camada de aplicação e se você precisa dela de fato. Se você chegar à conclusão de que não precisa, o jeito é você acessar a infraestrutura diretamente da camada de apresentação - leia-se, actions/managed beans;
  2. Veja que no diagrama do livro há também uma conexão entre as camadas de apresentação e infraestrutura.

Resumidamente, se você precisa de uma camada de aplicação, não faz sentido acessar a infraestrutura a partir da apresentação.[/quote]

Olá Tarso, obrigado pelas respostas. Então na minha opinião, acredito que só há necessidade de criar uma Camada de Aplicação, quando se trabalha com duas interfaces por exemplo como Swing e Html, ai tudo bem, pois não posso acoplar a camada de apresentação a minha interface, pois posso ter nomes diferentes nas camadas.

Então acho que no meu caso é justificado acessar a camada de persistencia diretamente. Como fala no artigo, uma camada não de nivel mais alto nao deve depender de outra de nivel mais baixo e sim de abstrações, então neste caso seria acessar uma interface Dao correto?

Esse é um dos motivos, mas não é o único. Por exemplo, a camada de aplicação é bastante útil para centralizar outros aspectos de infraestrutura que não persistência, como controle de transação e/ou logging. Você pode escrever sua aplicação sem essa camada, mas tem que arcar com os prejuízos de não adotá-la, se eles existirem. Dificilmente você sentirá esses prejuízos se seu sistema for apenas CRUD.

No meu caso controlo transação com Filters, mas achei interessante fazer loggin, na camada de Aplicação. Me responde outra coisa digamos que tenha na minha interface Dao findByCriterion(Criterion c), poderia ser de responsabilidade da camada de aplicação montar essses criterios tipo assim, usando JSF.

Camada de Apresentação

class FuncionarioBean{
  ApplicationLayer funcionarioFaçade //exemplo.
 public List<Funcionario> findByName(){

    funcionarioFacade.findByName(funcionario.getNome());
 
}

class FuncionarioFacade {
  private Dao funcionarioDao;

   public list<Funcionario> findBYName(String nome){
   Criterion c=Restrictions.ilike("nome",nome,MatchMode.ANYWHERE));
   return funcionarioDao.findByName(c); 
 
  }
}

   
}

O problema aqui seria a duplicação de metodos, mas tbm acho estranho criar um Criterion dentro da camada de aplicação, caso quissese usar um metodo deste tipo, qual seria a camada mais aconselhavel para se criar o Criterion?

Valeu, tem me ajudado muito!

[quote=danielbussade]Me responde outra coisa digamos que tenha na minha interface Dao findByCriterion(Criterion c), poderia ser de responsabilidade da camada de aplicação montar essses criterios tipo assim, usando JSF.

(…)

O problema aqui seria a duplicação de metodos, mas tbm acho estranho criar um Criterion dentro da camada de aplicação, caso quissese usar um metodo deste tipo, qual seria a camada mais aconselhavel para se criar o Criterion?[/quote]
Aí é melhor você jogar no repositório, que é onde estão localizados os métodos de consulta. A implementação do repositório se encarrega de utilizar o mecanismo de consulta referente à tecnologia de persistência que você está usando, seja Hibernate, JPA ou JDBC.

[quote=tnaires][quote=danielbussade]Me responde outra coisa digamos que tenha na minha interface Dao findByCriterion(Criterion c), poderia ser de responsabilidade da camada de aplicação montar essses criterios tipo assim, usando JSF.

(…)

O problema aqui seria a duplicação de metodos, mas tbm acho estranho criar um Criterion dentro da camada de aplicação, caso quissese usar um metodo deste tipo, qual seria a camada mais aconselhavel para se criar o Criterion?[/quote]
Aí é melhor você jogar no repositório, que é onde estão localizados os métodos de consulta. A implementação do repositório se encarrega de utilizar o mecanismo de consulta referente à tecnologia de persistência que você está usando, seja Hibernate, JPA ou JDBC.[/quote]

Então Tnaires, mas o repositorio não seria apenas uma interface? Antes eu teria que criar o Criterion, esse que e o problema onde criar este criterion.

Como você faz atualmente?

[quote=danielbussade]Então Tnaires, mas o repositorio não seria apenas uma interface? Antes eu teria que criar o Criterion, esse que e o problema onde criar este criterion.

Como você faz atualmente?[/quote]
Sim, o repositório pode ser uma interface, mas o que é uma interface sem sua implementação? Não funciona. Por exemplo, você acha que java.sql.Connection é apenas uma interface? O driver JDBC tem uma classe que implementa a interface Connection, mas ela não está visível pra nós.

Quando você constrói o repositório, é prudente sim fazer com que as classes externas ao pacote enxerguem apenas a interface, mas a implementação, apesar de não ser visível externamente, existe. E é ela que utilizará Criteria, HQL, SQL, XML ou o que for. E a vantagem de usar interfaces é que, se um dia sua aplicação deixar de utilizar JDBC para utilizar Hibernate, teoricamente será preciso apenas trocar as implementações dos repositórios - claro que outras mudanças relativas à configuração também serão necessárias.

Vejamos um exemplo. Temos um cadastro de clientes e temos uma consulta por nome do cliente. Haverá uma interface pública para o repositório de clientes:

[code]package domain;

public interface CustomerRepository {
Collection findByName(String name);
}[/code]Teremos sua implementação invisível para as classes fora do pacote. Note a visibilidade default para a classe:

[code]package domain;

class HibernateCustomerRepository implements CustomerRepository {
public Collection findByName(String name) {
// Código que cria um objeto Criteria e recupera os clientes cujo nome começam com “name”

    return result;
}

}[/code]E agora temos uma das possíveis formas de disponibilizar o repositório para as camadas que o utilizam, através de uma factory:

[code]package domain;

public class RepositoryFactory {
public static CustomerRepository getCustomerRepository() {
return new HibernateCustomerRepository();
}
}[/code]E se um dia der uma doida e tivermos que mudar de Hibernate para JDBC, será preciso criar uma nova implementação para o repositório…

[code]package domain;

class JDBCCustomerRepository implements CustomerRepository {
public Collection findByName(String name) {
// Código que cria um objeto PreparedStatement e executa um SQL para recuperar os clientes cujo nome começam com “name”

    return result;
}

}[/code]… e mudar o código da fábrica:

[code]package domain;

public class RepositoryFactory {
public static CustomerRepository getCustomerRepository() {
//return new HibernateCustomerRepository();
return new JDBCCustomerRepository();
}
}[/code]Foi um exemplo muito simples, mas que ilustra o que quero dizer.

[quote=tnaires][quote=danielbussade]Então Tnaires, mas o repositorio não seria apenas uma interface? Antes eu teria que criar o Criterion, esse que e o problema onde criar este criterion.

Como você faz atualmente?[/quote]
Sim, o repositório pode ser uma interface, mas o que é uma interface sem sua implementação? Não funciona. Por exemplo, você acha que java.sql.Connection é apenas uma interface? O driver JDBC tem uma classe que implementa a interface Connection, mas ela não está visível pra nós.

Quando você constrói o repositório, é prudente sim fazer com que as classes externas ao pacote enxerguem apenas a interface, mas a implementação, apesar de não ser visível externamente, existe. E é ela que utilizará Criteria, HQL, SQL, XML ou o que for. E a vantagem de usar interfaces é que, se um dia sua aplicação deixar de utilizar JDBC para utilizar Hibernate, teoricamente será preciso apenas trocar as implementações dos repositórios - claro que outras mudanças relativas à configuração também serão necessárias.

Vejamos um exemplo. Temos um cadastro de clientes e temos uma consulta por nome do cliente. Haverá uma interface pública para o repositório de clientes:

[code]package domain;

public interface CustomerRepository {
Collection findByName(String name);
}[/code]Teremos sua implementação invisível para as classes fora do pacote. Note a visibilidade default para a classe:

[code]package domain;

class HibernateCustomerRepository implements CustomerRepository {
public Collection findByName(String name) {
// Código que cria um objeto Criteria e recupera os clientes cujo nome começam com “name”

    return result;
}

}[/code]E agora temos uma das possíveis formas de disponibilizar o repositório para as camadas que o utilizam, através de uma factory:

[code]package domain;

public class RepositoryFactory {
public static CustomerRepository getCustomerRepository() {
return new HibernateCustomerRepository();
}
}[/code]E se um dia der uma doida e tivermos que mudar de Hibernate para JDBC, será preciso criar uma nova implementação para o repositório…

[code]package domain;

class JDBCCustomerRepository implements CustomerRepository {
public Collection findByName(String name) {
// Código que cria um objeto PreparedStatement e executa um SQL para recuperar os clientes cujo nome começam com “name”

    return result;
}

}[/code]… e mudar o código da fábrica:

[code]package domain;

public class RepositoryFactory {
public static CustomerRepository getCustomerRepository() {
//return new HibernateCustomerRepository();
return new JDBCCustomerRepository();
}
}[/code]Foi um exemplo muito simples, mas que ilustra o que quero dizer.[/quote]

Olá tnaires, é exatamente assim que faço. Mas o que quis dizer foi o seguinte, digamos que amanha vc queira pesquisar por login, e depois por cidade, teria que criar tres metodos certo?

findByLogin,
findByCidade

O que estou querendo fazer é ter um metodo bem generico, no repository, tipo como falei.

getByCriterion(Criterion);

e na implementacao seria

Criteria c=session.createCriteria(classe);
c.add(criterion);

Assim teria uma pesquisa generica podendo colocar OrderBy , Projections, etc.

O problema é que tenho q entregar este criterio pronto, vindo de outro lugar. Ai pergunto onde seria o melhro lugar para montar esse criterion.

Hj estou montando na Apresentação mas isso viola camadas, além de ficar feio.

Entendeu a minha duvida!

Onde, poderia colocar a montagem desses criterions?

Cara, como falei antes, não tem jeito. O melhor lugar pra montar esse Criterion é dentro dos métodos do repositório, como os que você citou: findByLogin, findByCidade, etc.
Agora o método genérico que você quer construir pode ficar em dois locais:

  1. Uma classe de utilitários;
  2. Uma classe abstrata - digamos HibernateRepository - da qual todas as implementações dos repositórios herdariam.

Afinal, voce ja decidiu se vai de ActiveRecord ou DDD?

Olá, onde você estava vendo ActiveRecord aqui?

Pois é, Daniel, eu tambem tenho essa mesma duvida sobre onde criar os criterions. Eu achei uma maneira que me ajuda a manter a interface do repositorio mais limpa, mas nao sei se é a ideal, talvez ainda nao seja.

Eu crio objetos “buscadores” que recebem os parametros e criam os criterions, depois sao passados para os repositorios com um clienteRepository.findByCriterios(buscadorDeCliente).

por exemplo:

buscadorDeCliente.setRazaoSocial("Pepsi");
buscadorDeCliente.setCidade("Sao Paulo");

Depois ele possui um metodo que retorna uma hql ou criteria ou sql ou qualquer coisa dependendo da implementacao, baseado nos parametros que foram informados.

A desvantagem é que preciso escrever um pra cada entidade da aplicacao.

E detalhe: Usuario salva outro usuário? Acho que AR, se trate de o usuário “se salvar”. ex.: user.save();

[quote=MrDataFlex][quote=danielbussade]
3- Criar um metodo save dentro De Usuario(ActiveRecord), e minha action/servlet chamar Usuario.save(usuario);
[/quote]

E detalhe: Usuario salva outro usuário? Acho que AR, se trate de o usuário “se salvar”. ex.: user.save();[/quote]

Exato, erro de Ctrl+ C e CTRL + V meu!

Orbigado!

Não tenho certeza se eu entendi a dúvida sobre criteria mas uma coisa que recomendo ao utilizá-lo em DDD é utilizar uma interface de Specifiation na Camada de Negócios e implementá-la com um Query Object na Persistência. É um equivalente à dobradinha Repositório/DAO.

Acho difícil estarem falando de DDD neste caso. Pelo que entendi a única motivação para o mecanismo de busca parte do cliente da camada de aplicação.

A lição que aprendi hoje, sempre se questione quanto a real necessidade de tantas abstrações que na verdade se mostram inúteis.