Juntar repository e collections é possível?

Cara, uma coisa é o conceito e a utilidade do repositorio. Outra coisa é ORM.
Misturar os dois dá merda.

O problema é que @manyToOne resolve em certas circusntâncias. Como já foi dito : se usar hibernate é tudo uma maravilha, mas se usar JDBC é um pesadelo. Mas Hibernate e JDBC são tecnologias de persistencia.
um repositorio (repositorio : onde vc coloca as coisas e depois pega de volta) não tem nada a ver com persistencia.
(persistir: manter por muito tempo)
Já existiram vários topicos sobre isto , e eu digo sempre a mesma coisa, então não vou me repetir. A questão é :

  1. Entender o papel do Repositorio. Entender que o repositorio serve escatamente para não existirem ActiveRecords. Entender que o repositorio é tão ou mais consciente das relações entre as entidades que a entidades elas mesmas.

  2. Entender que Repositorio é diferente de DAO. Eu sei que é dificil , mas ao menos tentem.
    Repositorio : prover acesso centralizado ao conjunto de instancias de uma entidade.
    DAO: prover acesso padronizado a N diferentes tencologias de persitencia cujas API não são equivalentes.

  3. Entender que se ( atenção ao SE) o sistema necessita de persistência então terá que haver um mapeamento entre o repositorio ( instancias em memoria) e o banco ( instancias persistidas).
    3.a) O repositorio deve funcionar da mesma forma para qualquer sistema de persistencia pois ele não dependente disso.

Exemplo de repositorio com persistencia


class RepositorioTurma {

     PersistenceAgent agent;
     RepositorioAluno repAlunos;

    public void add (Turma turma){

            agent.insertOrUpdate(turma);
            for (Aluno a : turma){
                 repAlunos.add(a);
            }

    }

}

Mais uma vez não chamei nada de DAO para que seja claro o papel de cada objeto.
Agora vc diz assim:

  1. “Mas porque colocar mais uma camada se posso chamar o agente de peristencia directamente ?”

O ponto é: Vc pode mas vc não quer. Se vc quer, vc não entender para que serve o repositorio.

  1. “Porque não implementar um repositorio generico?”

Vc pode implementar generico, mas o dominio deve ter acesso como se fosse individual
Mas é licito fazer algo como

E usar um mecanismo de injeção/fabrica. O ponto é que se eu pedir o repositorio de TipoDeProduto e eu não especificar qual implmentação quero, o metodo retorna uma implementação generica. Mas se eu definir um classe de implementação especifica, deve ser essa a retornada. O objetivo do repositorio é ter métodos especificos/especiais de busca que sejam directamente acoplados às regras de negocio.
Essa é uma grande diferença do DAO onde esses métodos devem ser fracamente acoplados às regras de negocio. Em DAO vc usa um criteria. No repositorio vc cria uma logica de negocio.

Um outro exemplo simples de como DAO e Repositorio são difernetes.
(sintaxe simplificada)


RepositorioAccountTransaction{

 public void addAccountTransaction(AccountTransaction t ){

    RecordMapper mapper = new RelectionMapper();
    mapper.exclude( new MoneyFieldFilter() ); // esclui campos to tipo Money
  
    Record t_rec = mapper.map(t);
    Money value = t.value;
    t_rec.setAmount(value.getAmount()); 
     
    persistenceAgent.insertOrUpdate(t_rec);

    RepositoryAccount.add(t.from);
    RepositoryAccount.add(t.to);

    
}

public List<Transactions> getTransactions(Date date){

     RecordQuery query = "from transaction where date = " + date; // simbolico

     List<Record> records =  persistenceAgent.execute(query); 

     List <Transactions> res = new ... 

     Currency c = Currency.newInstance("BRL"); // poderia ler de tabela
 
     for (Record r : records) {
             t =  mapper.unMap(r);
             t.value = new Money ( r.getAmount() , c);
             res.add(t);
     }
     
  return res;
}

}

}

Pode até haver um forma de setar Money com uma Currency usando Hibernate. Esse não é o ponto.
O ponto é que o repositorio sabe , onde e como encontrar as coisas e produzir objetos de dominio corretamente.
Ele sabe regras de dominio. DAOs não devem saver regras de dominio.

Não sei mais o que dizer…

[quote=Fabio Kung]Mas depende do caso. Naquela discussão de ter um repositório dentro de entidades ou não, se você escolhe por deixar repositórios dentro de entities, o repositorio acaba servindo para definir relacionamentos complicados como: “1 Turma possui N Alunos transferidos de outros estados”.

class Turma { private final RepositorioDeAlunos rep; ... public List<Aluno> getAlunosTransferidosDeOutrosEstados() { return this.rep.getAlunosTransferidos(<de>, <para>); } } [/quote]

Só para ficar claro: Nesta consulta é retornado os alunos transferido de um estado X para um estado Y e que seja desta turma, correto?

Pois nesta idéia de juntar a collection com o repository passa a ficar confuso se temos um repositório para todos os alunos persistidos no sistema ou se é apenas um repositório de alunos para uma turma em específico.

Afinal, é mais coerente uma turma ter seu próprio repositório de alunos ou ter um repositório de alunos para o domínio?

[quote=Thiago Senna]
Afinal, é mais coerente uma turma ter seu próprio repositório de alunos ou ter um repositório de alunos para o domínio?[/quote]

Repositorio é para todos os aluns.
Turma não precisa de um repositorio de alunos. Ela mesma contém os alunos! :shock:

class Turma {
 
    Collection alunos;

}

[quote=sergiotaborda][quote=Thiago Senna]
Afinal, é mais coerente uma turma ter seu próprio repositório de alunos ou ter um repositório de alunos para o domínio?[/quote]

Repositorio é para todos os aluns.
Turma não precisa de um repositorio de alunos. Ela mesma contém os alunos! :shock:

[/quote]

Sim, entendi! Mas o que quero agora é questionar isso. Se a turma já tem os alunos, para que também guardá-los em repositórios? Olhando por este ponto de vista não parece que estou tendo que trabalhar bem mais?

Só pra somar: se eu quiser persistir em XML por exemplo, basta que a collection seja uma implementação de XmlArrayList do XStream (http://xstream.codehaus.org/persistence-tutorial.html). Precisaria de alguns cuidados, mas é um objetivo tranquilamente alcançavel. Eu mato a persistência e o relacionamento em uma paulada só.

[color=red]UPDATED:[/color]
Imagine que posso fazer uma ‘DI’ e dizer qual é a implementação da collection que a aplicação deve utilizar? Deve dar um bom trabalho, mas parece ser possível colocar uma implementação de Collection encarregada de se manter sincronizada com um hibernate da vida.

Isso só acontece quando insistimos em colocar métodos de negócio dentro do DAO. Mas o DAO não foi feito pra isso.[/quote]
AHM??? Pode explicar isso? Quem disse isso?
[/quote]
Então você concorda que devemos colocar regras de negócio no DAO, que foi feito apenas para cuidar de questões envolvendo persistência?

Claro que existem situações onde isso é adequado, mas conceitualmente é errado.

Conforme afirmou o sergiotaborda:

A ideia não é injectar coleções, é injetar mecanismos de persistencia.
Para que isto dê certo as suas classes não devem depender do mecanismo.
Um mecanismo realmente generico é hand-off. Ou seja, ele pega seus objetos e faz o trabalho
de persistir. O máximo que podemos dar a estes mecanismos são metadados.

Usar classes especiais de Collection não dão certo.

Eu entendo o que quer dizer com ter que adionar em turma e depois em repositorio. O vc não está entendendo é que essa adição é transiente. Ou seja, se vc adicionar aluno a turma, mas se arrepender e não remeter turma ao repositorio com o seu mecanismo de “auto-adição” o aluno já fica no repositorio de alunos mesmo quando eu anular o processo.


Turma t = new Turma(); // 0 turmas, 0 alunos
Aluno a = new Aluno();  // 0 turmas, 0 alunos
t.addAluno(a);//  0 turmas, 1 alunos

// abort

O repositorio de alunos ficou com um aluno porque eu o adiconei em turma. Isto é um erro.
Enfim , a sua ideia simplesmente não funciona. Vc tem que olhar “the big picture” porque ha muitas coisas envolvidas e não apenas add/remove.

[quote=sergiotaborda]Repositorio é para todos os aluns.
Turma não precisa de um repositorio de alunos. Ela mesma contém os alunos! :shock:

class Turma {
 
    Collection alunos;

}

[/quote]
Sérgio, acho que depende. Se os requisitos do sistema exigirem que eu armazene alunos que não estão em turma alguma, então precisarei de um repositório explícito de alunos correto?

[quote=tnaires][quote=sergiotaborda]Repositorio é para todos os aluns.
Turma não precisa de um repositorio de alunos. Ela mesma contém os alunos! :shock:
[/quote]
Sérgio, acho que depende. Se os requisitos do sistema exigirem que eu armazene alunos que não estão em turma alguma, então precisarei de um repositório explícito de alunos correto?[/quote]

Concerteza. Vc sempre terá um repositorio de alunos. O repositorio representa TODOS os alunos que existem no dominio. Alguns estarão agrupados em turmas outros não.
Agora, no grafo da turma, têm que estar os alunos. Claro que em termos de implementação vc pode simular que os alunos estão na turma sem usar uma coleção implicita. mas isso complica a longo praso. Quanto mais desacoplado for a entidade do repositorio melhor.

// opção de não usar collectino em turma

Turma {

   List<Aluno> getAlunos(){
          return AlunosRepository.getAlunos(this);
   }

   addAluno ( Aluno aluno) {
          AlunosRepository.addAlunoTurma(this, aluno);
   }
}

[quote=sergiotaborda]Cara, uma coisa é o conceito e a utilidade do repositorio. Outra coisa é ORM.
Misturar os dois dá merda.

O problema é que @manyToOne resolve em certas circusntâncias. Como já foi dito : se usar hibernate é tudo uma maravilha, mas se usar JDBC é um pesadelo. Mas Hibernate e JDBC são tecnologias de persistencia.[/quote]
Ahn?
Problema: quero os alunos dada uma turma.

ORM decente: List<Aluno> alunos = turma.getAlunos();
JDBC Puro: List<Aluno> alunos = repositorio.getAlunosDa(turma);

Sem ter um repositório dentro da entidade, não há como fazer a primeira alternativa usando jdbc puro. Portanto a escolha de usar um orm decente impacta sim em como você vai usar os seus repositórios. Não dá para nivelar sempre por baixo e fazer tudo como se você estivesse usando só JDBC puro. Para que ignorar o fato de que existe um ORM que permite níveis de abstração maiores?

[quote=sergiotaborda]um repositorio (repositorio : onde vc coloca as coisas e depois pega de volta) não tem nada a ver com persistencia.
(persistir: manter por muito tempo)
Já existiram vários topicos sobre isto , e eu digo sempre a mesma coisa, então não vou me repetir.

  1. Entender o papel do Repositorio. Entender que o repositorio serve escatamente para não existirem ActiveRecords.
  2. Entender que Repositorio é diferente de DAO. Eu sei que é dificil , mas ao menos tentem.
    Repositorio : prover acesso centralizado ao conjunto de instancias de uma entidade.
    DAO: prover acesso padronizado a N diferentes tencologias de persitencia cujas API não são equivalentes.

[/quote]
Sérgio, eu acho muito válido você explicar quantas vezes você quiser o que é Repositório. Mas acho que para mim não precisa. O que eu disse não é um indicativo de que eu não sei o que são Repositórios e o que eles representam.

[quote=sergiotaborda]A questão é :
Entender que o repositorio é tão ou mais consciente das relações entre as entidades que a entidades elas mesmas.[/quote]

Você se contradiz aqui. O repositório que cuida das relações mas a Turma mantém a relação?

Isso é nivelar por baixo. A escolha do framework orm impacta sim onde você vai ou não precisar de um repositório.

[quote=sergiotaborda]
O ponto é que o repositorio sabe , onde e como encontrar as coisas e produzir objetos de dominio corretamente.
Ele sabe regras de dominio. DAOs não devem saver regras de dominio.[/quote]
Eu só não entendi o que todo o seu discurso sobre Repository vs Dao tem a ver com o meu comentário, de que você não precisa fazer com que todas as relações entre os objetos devam ser gerenciadas pelo repositório. A engine de orm resolve isso para mim em vários casos, a um custo bem menor.

Claro que @ManyToOne não resolve tudo. Aí você tem várias alternativas, entre elas:

  1. Criar um novo relacionamento para implementar o seu requisito:

[code]class Turma {
@OneToMany
private List<Aluno> alunos;

@OneToMany
private List<Aluno> alunosComNotaMaiorQueDez;
}[/code]

  1. Repositorio dentro da turma e fazer:
  1. ou finalmente:

[quote=sergiotaborda]Quanto mais desacoplado for a entidade do repositorio melhor.

[code]
// opção de não usar collectino em turma

Turma {

List<Aluno> getAlunos(){
return AlunosRepository.getAlunos(this);
}

addAluno ( Aluno aluno) {
AlunosRepository.addAlunoTurma(this, aluno);
}
}
[/code][/quote]
Você não percebe que esse seu repositório não tem NADA de diferente de uma Collection?

[code]class Turma {
List<Aluno> alunos;

List<Aluno> getAlunos(){
return this.alunos;
}

addAluno(Aluno aluno) {
this.alinos.add(aluno);
}
}[/code]
Collections são repositorios!

[quote=Thiago Senna]Só pra somar: se eu quiser persistir em XML por exemplo, basta que a collection seja uma implementação de XmlArrayList do XStream (http://xstream.codehaus.org/persistence-tutorial.html). Precisaria de alguns cuidados, mas é um objetivo tranquilamente alcançavel. Eu mato a persistência e o relacionamento em uma paulada só.

[color=red]UPDATED:[/color]
Imagine que posso fazer uma ‘DI’ e dizer qual é a implementação da collection que a aplicação deve utilizar? Deve dar um bom trabalho, mas parece ser possível colocar uma implementação de Collection encarregada de se manter sincronizada com um hibernate da vida.[/quote]

Isso é verdade Thiago. Mas fazer seu repositorio implementar Collection não faz com que você possa injetar uma implementação de Collection do XStream, justamente pq vc não usa o Repositorio como Collection. Você precisa usar os metodos especificos:

[code]
class Turma {
// nao estou injetando so para deixar claro que vc quer usar o repositorio como lista…
private List<Aluno> alunos = new AlunoRepository();

public getAlunosComNotaMaiorQue(int nota) {
// nao consigo usar os metodos especificos do repositorio…
}
}[/code]
No fim das contas, o que vc vai acabar usando na sua Entidade é:

[code]
class Turma {
// nao estou injetando so para deixar claro que vc quer usar o repositorio como lista…
private AlunoRepository alunos = new AlunoRepository();

public getAlunosComNotaMaiorQue(int nota) {
return alunos.blablabla(nota, this);
}
}[/code]
E aí não adianta você querer injetar nessa entidade uma implementação de List qualquer. A XmlList do XStream (viu o @author dela? :smiley: ) não tem o metodo blablabla().

Pegou?

Quando vc recupera os dados para reconstruir a turma, não recupera tbm a coleção de alunos que é atributo da turma? (Excetuando os casos de lazy loading)

Concordo e o próprio Evans escreveu sobre isso:

Mas… o add/remove é mesmo o menor dos problemas. Mas inicialmente, se eu levasse essa idéia pra frente tentando implementar algo, imagino que não preciso nem ao menos sobrescrever add/remove. Eles já estariam prontos, do jeito que estão hoje. Eu só quero acrescentar nestas collections buscas mais específicas. A implementação destas buscas mais específicas seria delegado para o mecanismo de persistência.

Se o assunto é JDBC, o bicho pega. Mas se fosse possível:

turma.getAlunos().getAdicionados(); turma.getAlunos().getAlterados(); turma.getAlunos().getRemovidos();
Aí, lá no DAO você poderia usar estes métodos para sincronizar com o BD. Mas isso é só uma idéia. Não leve este exemplo a sério, hehe! Mas isso é em IMHO um exemplo de que as collections poderiam ser mais espertas.

Se o assunto é hibernate o negócio é mais fácil. Até a injeção de dependência talvez fique mais fácil, pois nem vai precisar (em parte). Os dados que são inseridos e removidos da coleção o próprio hibernate gerencia à partir dos mapeamentos. Só preciso mesmo do gran finale de como implementar a coleção sem ter muito trabalho (sou muito preguiçoso, hehe).

imagine:

[code]turmas = session.find(“from Turma”); // coloquei o session hibernate aqui de propósito

for (Turma t: turmas) {
List alunos = t.getAlunosReprovadosNoAnoAnterior();
// o hibernate já garante que alunos na verdade seja uma coleção de AlunoPersistentCollection, por exemplo
}
[/code]

O difícil mesmo é como fazer isso tudo! Mas se houver uma solução ténica viável e elegante, ai como fica o Repository? Ainda justificaria? Talvez aí comece a ser uma questão de gosto :slight_smile:

Achei três artigos que não li ainda com o devido cuidado, mas parece ser um assunto similar ao que está sendo discutido neste tópico.

Custom Collections with NHibernate, Part I: Refactored - Billy McCafferty
Custom Collections with NHibernate, Part II: Refactored - Billy McCafferty
Custom Collections with NHibernate, Part III: Refactored - Billy McCafferty

[quote=Fabio Kung]No fim das contas, o que vc vai acabar usando na sua Entidade é:

[code]
class Turma {
// nao estou injetando so para deixar claro que vc quer usar o repositorio como lista…
private AlunoRepository alunos = new AlunoRepository();

public getAlunosComNotaMaiorQue(int nota) {
return alunos.blablabla(nota, this);
}
}[/code]
E aí não adianta você querer injetar nessa entidade uma implementação de List qualquer. A XmlList do XStream (viu o @author dela? :smiley: ) não tem o metodo blablabla().

Pegou?

[/quote]

Mais ou menos, Fabio. E se AlunoRepository é uma interface e:

Poderia encapsular com composição por exemplo o XmlList, não posso?

E se

Então esse código:

public getAlunosComNotaMaiorQue(int nota) { return alunos.blablabla(nota, this); }

poderia ficar assim:

public getAlunosComNotaMaiorQue(int nota) { return alunos.blablabla(nota); }
Tirei o this, pois se estou juntando collection + repository é melhor que a própria collection saiba qual é a turma que ele está relacionado. Por isso usei: “new RepositoryFactory.getAlunoRepositoryHibernateImpl(this)”

Sobre o autor do XmlList, eu já vi quem é o autor sim. Aliás, todo aquele pacote ‘persistence’ é tudo do mesmo autor. Será que posso confiar(risos)?

Caso eu tenha escrevido todo este post e não tenha conseguido contornar o problema que você viu, é por que eu não peguei o problema :frowning: Caso seja este o caso, explique denovo, por favor!

[quote=Fabio Kung][quote=sergiotaborda]Cara, uma coisa é o conceito e a utilidade do repositorio. Outra coisa é ORM.
Misturar os dois dá merda.

O problema é que @manyToOne resolve em certas circusntâncias. Como já foi dito : se usar hibernate é tudo uma maravilha, mas se usar JDBC é um pesadelo. Mas Hibernate e JDBC são tecnologias de persistencia.[/quote]
Ahn?
Problema: quero os alunos dada uma turma.

ORM decente: List&lt;Aluno&gt; alunos = turma.getAlunos();
JDBC Puro: List&lt;Aluno&gt; alunos = repositorio.getAlunosDa(turma);

Sem ter um repositório dentro da entidade, não há como fazer a primeira alternativa usando jdbc puro. Portanto a escolha de usar um orm decente impacta sim em como você vai usar os seus repositórios. Não dá para nivelar sempre por baixo e fazer tudo como se você estivesse usando só JDBC puro. Para que ignorar o fato de que existe um ORM que permite níveis de abstração maiores?

[/quote]

E depois vc se interroga porque fico explicando a diferença entre repositorio e DAO.
Um mecanismo ORM é um tipo especifico de DAO. Então não interessa que mecanismo eu estou usando para a persistencia porque o DAO me isola disso. Esse é o papel do DAO: isolar a API de persistencia. Seja JDBC, seja Hibernate seja o que for.
Eu posso fazer List<Aluno> alunos = turma.getAlunos() em qualquer esquema de persistencia. Eu não apenas posso, como DEVO. Porquê? Pela simples razão que esse código representa uma relação direta entre turma e aluno. É uma relação de dominio. É uam relação do modelo! Não devo simplesmente usar o segundo codigo. Pelo menos não se estiver usando DDD.

(Tlv seja uma falha minha, mas se a pessoa fala em repositorio eu assumo que ela está usando DDD e portanto o objetivo final é ter classes de dominio corretas. Agora, se vc está falando fora de DDD ai vc faz o que quiser e como quiser. Só que se vc falar de repositorio fora de DDD não faz sentido absolutamente nenhum. Já que se não um modelo de dominio bem definido, vale tudo.)

Depois vc está esquecendo que as classes do dominio/modelo são desacopladas da intraestrutura. Logo, aquele codigo vai funcionar em qualquer ocasião porque o Repositorio vai se encarregar que assim seja. Que truques o repositorio usa para fazer isso não interessa. O que interessa é que vc SEMPRE vai poder usar o modelo na sua forma pura sem recurrer a truques ou a métodos “globais” como repositorio.getAlunosDa(turma).
Usar este tipo de codigo é fazer modelos orientados a banco de dados e não modelos OO.

de um lado da moeda:
O objeto turma mantém as suas relações de MODELO. A turma tem alunos e está assignada a professores.
Tem um horario, etc… No modelo, Turma tem tantas relaçoes como a turma real tem no mundo real.
O objeto turma é consciente que tem uma coleção de alunos associada a ele e ele permite acesso a ela com getAlunos(). Isto é modelagem. Isto é orientação a dominio.

do outro lado da moeda:
O repositorio da turma tem que garantir que o objeto turma seja incluido na lista de turmas existentes e que o seu estado seja conservado. Porque quando o dominio puxar um “getTodasTurmas()” essa turma tem que estar lá. E tem que estar lá com todo o seu grafo de objetos relacionados. Alunos, Professores, etc…
O ponto é que o repositorio da turma sabe conservar turmas. Apenas turmas. Portanto ele tem que delegar a outros repositorios a conservação dos outros tipos. O ponto é que ele sabe como uma turma é formada. O repositorio é um objeto do dominio. Ele tem conhecimento das entidades e das suas relações e ele vigia que essas relações seja mantidas de forma coerente. Então, o repositorio sabe que turma tem vários alunos e professores e ele sabe que tem que delegar a conservação desses tipos aos repositorios apropriados.
Isto ainda é orientação ao dominio, mas agora não do ponto de vista da turma individual, mas do ponto de vista do cara que tem que manter todas as turmas. O objeto turma está preocupado em manter um coleção dos seus alunos. Os repositorios estão preocupados em manter a coleção e todas as turmas e todos os alunos.

O primeiro caso vc resolve facil com uma coleção privada e desacoplada : um arraylist da vida.
O segundo caso vc não resolver apenas um coleções porque vc precisa de alguma logica que destinga de entre todos os alunos do sistema, quais pertencem a qual turma.

Na “cabeça” de um repositorio não existem bancos de dados. Existem coleções de objetos e relações entre eles que têm que ser mantidas. Mas elas são mantidas com logica programada no repositorio e não com mecanismos externos.

Por isso que ue falei que é necessário entender a diferença entre repositorio e DAO e onde fica a fronteira.
As informações de um repositorio não têm obrigação de ser persistentes. A persistencia é um mecanismo artificial que permite que o programa deixe de executar e depois volte a executar como o estado inalterado. Só isso. Não é a razão de vida de um sistema. Muito menos de um repositorio.

Para descobrir os alunos com nota maior que 8 não é necessário um repositório inteligente. Apenas um serviço que faça esse processo. E funciona ± assim:


Service {

public List&lt;Aluno&gt; alunosNotaMaior(Disciplina d , int nota){
 
     RepositorioAlunos rep= ...  
     List&lt;Aluno&gt; alunos = new LinkedList(rep.getAll());

     for ( Iterator it = alunos .iterator(); it.hasNext();){
                 Aluno aluno = it.next();
                 if ( ! (aluno.getNota ( d )  &gt; nota )){
                          it.remove();
                 }
     }
      return alunos;


}

}

Não. A escolha de ter um repositorio se deve a vc querer um modelo simples, rico e independente de estrutura.
Vc tem um repositorio se vc está querendo esses objetivos.
Se além disso vc quer persistencia, vc tem um DAO ( que pode ser JDBC puro sim)
Se além disso vc quer ter um mecanismo padrão para o DAO com JDBC vc usa ORM.
Entenda que ORM não é o objetivo é apenas uma ferramenta.
se o o seu DAO é JCache ou JGroups não ha ORM. Se o seu dao é XML não ha ORM.

Se a escolha do ORM inpacta o seu modelo então para que serve o DAO ? Afinal que isolamento é esse ? Isolamento poroso ? Se o ORM impacta o modelo o seu sistema é fortemente acoplado. Pior ainda, só funciona dessa maneira. Então para quê complicar com DAO e repositorios ? Arranque isso fora , deixe o ORM puro e pronto. Vai ganhar um monte em simplicidade e poupar um monte de camadas inuteis no seu sistema.

Os padrões têm objetivos. Se vc não tem esses objetivos porque usar os padrões ? Moda ?

Eu já falei isto tantas vezes mas parece que não me consigo fazer entender. :cry:

Quando vc recupera os dados para reconstruir a turma, não recupera tbm a coleção de alunos que é atributo da turma? (Excetuando os casos de lazy loading)
[/quote]
Pode sim. Mas aí você vai acabar fazendo o seu próprio ORM, concorda? Vai ter que cair nessas questões de implementar ou não lazy-loading já que é proibitivo trazer todos os relacionamentos sempre. Aí acaba caindo no caso de usar um orm (mesmo que seja você mesmo que fez).

[quote=Laércio Queiroz]Concordo e o próprio Evans escreveu sobre isso:

[quote=Evans]
“Before implementing something like a REPOSITORY , you need to think carefully about the infrastructure you are committed to, especially any architectural frameworks. You may find that the framework provides services you can use to easily create a REPOSITORY , or you may find that the framework fights you all the way. You may discover that the architectural framework has already defined an equivalent pattern of getting persistent objects. Or you may discover that it has defined a pattern that is not like a REPOSITORY at all.”

“In general, don’t fight your frameworks. Seek ways to keep the fundamentals of domain-driven design and let go of the specifics when the framework is antagonistic. Look for affinities between the concepts of domain-driven design and the concepts in the framework. This is assuming that you have no choice but to use the framework. Many J2EE projects don’t use entity beans at all. If you have the freedom, choose frameworks, or parts of frameworks, that are harmonious with the style of design you want to use.”[/quote][/quote]
Nem lembrava que ele tinha escrito isso. Obrigado!

[quote=Thiago Senna]Mais ou menos, Fabio. E se AlunoRepository é uma interface e:

Poderia encapsular com composição por exemplo o XmlList, não posso?[/quote]
Não só pode como deve. O exemplo de repositório que eu estava dando fazia justamente isso, mas a composição era com org.hibernate.Session ao invés de XmlList. Duas implementações do repositorio (mesma interface).

Não sei se você está vendo neste caso, que não houve nenhuma necessidade de ter implementado da interface Repository estender a interface List. Você nunca referencia o repositorio como List. Sempre como repositorio.

Implementar List, não te trouxe vantagem alguma. Viu agora?

Eu não estou questionando sua implementação de persistência com Listas persistentes. O ponto é que fazer o Repositorio implementar List não está trazendo vantagem alguma.

Concordo com você Fábio, só quis dizer que apesar de ser chato (e desnecessário em vários casos) … é possível fazer isto com JDBC puro. :wink:

Lendo as observações, tentei montar algo mais elaborado, não sei se peguei bem o espirito.

Abstrai a lógica da persistencia

[code]interface Repository {
PersistenceStrategy getStrategy();
void setPersistenceStrategy(PersistenceStrategy strategy);
}

interface PersistenceStrategy {
void store(T entity);
Collection list();
Collection list(Specification specification);
}[/code]

Apenas para exemplificar, persistencia baseada em collection

[code]class MemoryPersistenceStrategy implements PersistenceStrategy {
Collection c = new ArrayList();

@Override
public Collection<T> list() {
	return c;
}

@Override
public Collection<T> list(Specification specification) {
	ArrayList<T> result = new ArrayList<T>();
	for (T entity : list()) {
		if (specification.isSatisfiedBy(entity))
			result.add(entity);
	}
	return result;
}

@Override
public void store(Object entity) {
	c.add((T) entity);
}

}[/code]

Usa objetos Specification para interagir com o Repository

interface Specification<T> { boolean isSatisfiedBy(T entity); }

Exemplos de Specification

[code]class NotaAbaixoDaMediaSpecification implements Specification {
private int notaDeCorte;

public NotaAbaixoDaMediaSpecification(int notaDeCorte) {
	this.notaDeCorte = notaDeCorte;
}

@Override
public boolean isSatisfiedBy(Aluno entity) {
	return (entity.getNota() < notaDeCorte);
}

}

class AlunosDaTurmaSpecification implements Specification {
private Turma turma;

public AlunosDaTurmaSpecification(Turma turma) {
	this.turma = turma;
}

@Override
public boolean isSatisfiedBy(Aluno entity) {
	return entity.getTurma() == turma;
}

}[/code]

Um exemplo de repository

[code]class AlunoRepository implements Repository {
private PersistenceStrategy persistenceStrategy;

@Override
public PersistenceStrategy<Aluno> getStrategy() {
	return persistenceStrategy;
}

@Override
public void setPersistenceStrategy(PersistenceStrategy<Aluno> strategy) {
	this.persistenceStrategy = strategy;
}

public Collection<Aluno> list() {
	return persistenceStrategy.list();
}

public Collection<Aluno> list(Specification<Aluno> specification) {
	return persistenceStrategy.list(specification);
}

public void store(Aluno entity) {
	persistenceStrategy.store(entity);
}

}[/code]

O aluno, bem simples

[code]class Aluno {
private String nome;
private int nota;
private Turma turma;

public Aluno(String nome, int nota) {
	this.nome = nome;
	this.nota = nota;
}

public String getNome() {
	return nome;
}
public int getNota() {
	return nota;
}
public Turma getTurma() {
	return turma;
}
void setTurma(Turma turma) {
	this.turma = turma;
}
public String toString() {
	return getNome()+" "+getNota();
}

}[/code]

E a turma, tb bem básico, no caso eu passei o repositorio de alunos via construtor.
Aqui vejo um possível problema, turma tem acesso a todos os lunos através do repositorio, uma turma tem de gerenciar os seus alunos e seu conhecimento deveria se restringir a eles.

[code]class Turma {
AlunoRepository alunoRepository;

public Turma(AlunoRepository alunos) {
	alunoRepository = alunos;
}

public void increverAlunoNaTurma(Aluno aluno) {
	aluno.setTurma(this);
	alunoRepository.store(aluno);
}

public Collection<Aluno> getAlunos() {
	return alunoRepository.list(new AlunosDaTurmaSpecification(this)); 
}

}[/code]

Um pqno teste para ver funcionando

[code]public class Teste {

public static void main (String args[] ) {
	AlunoRepository alunos = new AlunoRepository();
	alunos.setPersistenceStrategy(new MemoryPersistenceStrategy<Aluno>());
	
	Turma turmaA = new Turma(alunos);
	turmaA.increverAlunoNaTurma(new Aluno("José", 6));
	turmaA.increverAlunoNaTurma(new Aluno("João", 7));
	turmaA.increverAlunoNaTurma(new Aluno("Maria", 8));
	Turma turmaB = new Turma(alunos);
	turmaB.increverAlunoNaTurma(new Aluno("Ana", 7));
	
	Specification<Aluno> notaAbaixo = new NotaAbaixoDaMediaSpecification(8); 
	System.out.println("=== Alunos da Turma A");
	for (Aluno a : turmaA.getAlunos()) {
		System.out.println(a);
		if (notaAbaixo.isSatisfiedBy(a))
			System.out.println(" Abaixo da Média");
	}
	System.out.println("=== Alunos da Turma B");
	for (Aluno a : turmaB.getAlunos()) {
		System.out.println(a);
		if (notaAbaixo.isSatisfiedBy(a))
			System.out.println(" Abaixo da Média");
	}
	System.out.println("Fim");
}

}[/code]

Se quizesse mudar para Hibernate e/ou JDBC, teria de implementar HibernatePersistenceStrategy ou JdbcPersistenceStrategy.
O problema cai no Strategy. Minha idéia seria usar um Filter (na falta de nome melhor e para não confundir com Criteria do hibernate), onde pudesse montar as restrições, e o PersistenceStrategy converteria esse Filter para a linguagem correta Filter -> Criteria ou Filter -> HQL ou Filter -> AnsiSQL

Seria esse um caminho ou seria exagero?