Repository: seu modelo mais Orientado a Objeto

Postado em 09. jun, 2007 por em Java

Já tem algum tempo que a excelente discussão no GUJ estava me motivando a escrever a respeito.

Para ambientar, a principal discussão é usar:

Fornecedor fornecedor = ...;
List contas = dao.carregaContasPagasDesde1999(fornecedor);

Ou:

Fornecedor fornecedor = ...;
List contas = fornecedor.getContasPagasDesde1999()

Já que posts na forma de diálogos costumam ser muito interessantes, aproveito um papo que eu e o Paulo Silveira tivemos.

Paulo: credo, achei horroroso isso da classe de domínio acessar o repositório
Paulo: mas fica bonitinha a sentença

Fabio: horroroso pq? vc prefere procedural?
Fabio: repositório é domínio tb
Fabio: um List, um Map são repositórios
Fabio: vc acha acessar List e Map horroroso?

Paulo: tem certa razão
Paulo: mas entao poderia chamar o DAO diretamente de repositório

Fabio: em muitos casos poderíamos
Fabio: eu só estava pensando num jeito legal de injetar

Paulo: desde que o cara não receba os objetos de dominio

Fabio: talvez com interceptor de session, ou listener
Fabio: ou então injeta nos métodos load()

Paulo: então. Complicado um Usuario sempre precisar de Repositorio!

Fabio: todo usuário não
Fabio: só Usuário Managed
Fabio: quando vc dá new num Usuário, vc tb não consegue navegar em relacionamentos
Fabio: só faz sentido pegar relacionamento em managed

Paulo: certo
Paulo: mas olha só
Paulo: vai ter Usuario com repositório e outro sem
Paulo: em alguns vc vai poder chamar o método que faz buscas, em outros não

Fabio: mas isso já é assim

Paulo: não com o dao

Fabio: imagina Usuario @OneToMany Categoria

Paulo: certo

Fabio: vc só consegue chamar usuario.getCategorias() no managed, mesma coisa
Fabio: só vai poder chamar usuario.getCategoriasEspeciais() no managed
Fabio: não adianta dar new Usuario().getCategoriasEspecias();

Paulo: hum… entendi! Podia ser um interceptor como fizemos no caelumweb
Paulo: aí ele setava um atributo privado

Fabio: Ou então o próprio load do dao/repository pode fazer isso.

Paulo: mas sei la, baita arquiteturazinha complicada

Fabio: nada! só injetar o repositório
Fabio: o resto é simples
Fabio: em vez de chamar no dao, que é procedural, chama via getter

Paulo: não não, você tem razão. É facílimo de implementar
Paulo: mas tipo, é muita coisa

Fabio: muita coisa do jeito que estão falando no tópico do GUJ! 500 camadas…
Fabio: Repository não precisa nem ser interface

Paulo: aquele interceptador que fizemos para gravar no lucene já não gosto muuuuito

Fabio: Repository pode ter referência para Session
Fabio: e não precisa injetar o repositorio na entidade com listener/interceptor
Fabio: poderia ser:

public class Repository {
  private final Session session;
  public Repository(Session session) {
    this.session = session;
  }

  public void get(Long id) {
    // poderia delegar para um dao, se fosse necessário
    Usuario u =  session.load(id);
    u.setRepository(this);
  }
}

Fabio: ou seja, na hora que você recupera uma Entidade managed, ela já vem com o repositório embutido…

Paulo: dessa maneira dá um pouco mais de responsabilidade para os beanzinhos entidades né? fica legal

Fabio: isso!

Paulo: proximo projeto vamos tentar essa abordagem?

Fabio: demorou… ;)
Fabio: hoje em dia, se vc quiser mostrar um objeto e alguma pesquisa personalizada, vc tem que consultar o objeto e a lista nas lógicas
Fabio: separados! E aí ejetar os dois
Fabio: muito feio
Fabio: geralmente faz-se isso (código usando algum controlador ruinzinho):

public class Logica { // extends Action? ;)
  public void mostraFornecedorEContasPagas() {
    Long id = request.getParameter("id"); // século passado...
    Fornecedor f = fornecedorDAO.load(id)
    List<Conta> contasPagas = contasDAO.listaContasPagasDoMes(fornecedor);
    // ejeta tudo para mostrar na view. No século passado seria:
    request.setAttribute("fornecedor", fornecedor);
    request.setAttribute("contasPagas", contasPagas);
  }
}

Fabio: MUITO procedural!

Paulo: cara se aplicarmos essas idéias, com velocity isso ia ficar ANIMAL
Paulo: Ia dar para chamar os métodos a la DAO direto no beanzinho

Fabio: ISSO!

Paulo: #foreach contas in contas.desde(1994)

Fabio: é meu, legal né?
Fabio: com JSP EL dá tb

Paulo: mais ou menos, teriamos de mexer nos evaluators

Fabio: não, soh usar padrão javabean
Fabio: ahhh vc quer passar parâmetro, aí EL não rola mesmo
Fabio: mas é puro DDD, já fiquei pensando bastante sobre o assunto
Fabio: ultimamente que tenho enxergado um jeito legal de aplicar

Paulo: bacana
Paulo: acho q vale a gente testar
Paulo: parava de ficar enfiando getters para expor as coisas para view.
Paulo: FABIO TODO: blogar sobre isso

Feito! ;)

Fabio Kung

Tags: , ,

24 Respostas para “Repository: seu modelo mais Orientado a Objeto”

  1. xebe

    13. jun, 2007

    Fabio, excelente este post.
    Como ficaria sua classe Fornecedor seguindo este seu modelo?
    Obrigado.

  2. Daniel Souza

    14. jun, 2007

    é, gostaria de saber tbm
    como ficaria Fornecedor ??

  3. Fabio Kung

    15. jun, 2007

    Recomendo que vocês leiam o tópico do guj (link no começo deste post) na integra. Tem várias alternativas de como ficaria o Fornecedor. Uma alternativa poderia ser:

    public class Fornecedor {
      private final FornecedorRepository repo;
      public Fornecedor(FornecedorRepository repo) {
        this.repo = repo;
      }
      public List getContasDesde(Date date) {
        return repo.getContas(this, date);
      }
    }

    Eu sei que é simplista demais. Esse é apenas um dos jeitos.

  4. Felipe Regalgo

    21. jun, 2007

    E se eu quisesse obter uma lista de todos os Fornecedores do sistema??
    esse metodo ficaria dentro da classe Fornecedor?? tipo:

    public class Fornecedor {
    private final FornecedorRepository repo;

    public Fornecedor(FornecedorRepository repo) {
    this.repo = repo;
    }
    public List getTodosFornecedores() {
    return repo.getTodosFornecedores();
    }
    }

    vc não acha melhor que essa funcionalidade não exista na classe Fornecedor e seja acessada chamando diretamente do repositorio (que faz parte do dominio)? por exemplo:

    fornecedorRepository.getTodosFornecedores();

    ao inves de

    fornecedor.getTodosFornecedores();

    a final de contas estamos querendo saber uma informação especifica de todos os fornecedores, e não daquele especifico!!!

    VAleu,
    e parabéns pelo post

  5. Paulo Silveira

    21. jun, 2007

    Felipe, ai voce usa o dao mesmo. Esse esquema é para deixar o objeto mais poderoso e com mais responsabilidade, mas nao faz sentido colocar nele um método de instância com cheiro de estático….

  6. Fabio Kung

    21. jun, 2007

    Boa Felipe,

    Essa é a velha discussão sobre ActiveRecord x DataMapper, mas nesse caso (e em Java) eu faria repository.getTodosFornecedores().

  7. Alexandre F. da Silva [afsrj]

    21. jul, 2007

    Eu gostei e nao gostei.
    So vale se for para o mesmo objeto(instância, this!) se for pra trazer coisas do tipo, fornecedor.getContasPagar() trazer de uma outra instância porque voce permitiu no conta a pagar pegar o getId, e liberou o acesso do setId ao inves de ser pelo construtor.

    Juro que vomitaria!

  8. Leila

    30. jan, 2008

    Boa sorte Juliano! vai em frente! vc é um cara de futuro ainda! hehehehe

  9. Emerson Moretto

    12. fev, 2008

    Eae Fabin!!

    parabéns pelo post cara!! Excelente! Ultimamente estive lendo o livro DDD do Eric Evans… e esse seu tópico veio a complementar muita coisa… talvez não tenha resolvido meus problemas, mas provavelmente tenha me trazido mais dúvida rsrsrs! (e isso é muito bom!)

    Estou implementando um projeto lá no LSI dessa forma que você sugeriu.. ou pelo menos uma tentativa do repositório injetado automaticamente ao entrar no estado “managed”.

    mais uma vez, parabéns!! você ta cada vez mais prodígio!! rsrsr
    abraços

  10. Dirceu

    16. set, 2008

    Eu até agora não sei o que é exatamente um Repositório.
    Seria uma espécie de ligação entre o DAO na camada de persistência e o domínio?? E não tenho a menor idéia de para que ele serve!

  11. Rômulo

    21. jul, 2009

    E se eu tiver 2 implementações para o DAO (JDBC e Hibernate) mas quiser isolá-las usando o Repository, ficando assim transaparente para o cliente, como faria para que minha aplicação tivesse esse suporte?

    Eu consigo fazer uma interface em comum para os dois, mas na hora de injetar como faria para dar suporte as 2 implementações? Porque no meu caso é possível que o cliente prefira usar, em algum momento, o JDBC porém o padrão seria Hibernate.

  12. Rômulo Augusto

    08. jul, 2011

    Tópico antigo, mas tenho uma pergunta que não vi nos comentários:

    O que você acha de também, além do construtor, um método específico receber um repositório como parâmetro?

    Por exemplo, para o caso do fornecedor:
    forncedor.getConstasDesde(1994, fornecedores);

    onde “fornecedores” seria o repositório.
    Isso seria legal para o caso em que o Hibernate cria os objetos Fornecedor. Assim não me preocuparia em alguma forma de injetar nessa criação.

    O que acham?

Trackbacks/Pingbacks

  1. IDLs para REST » Nullability » Some crappy scraps on software development - junho 10, 2007

    [...] posts em forma de diálogos estão se tornando moda (1 e 2) e como eu não tenho tido muito tempo para escrever decentemente sobre coisas que eu gosto, então [...]

  2. Comments to Gavin King about DDD and Repositories | Fabio Kung - novembro 12, 2007

    [...] about Repositories. I’m from Brazil and we have discussed it many times here (see at GUJ and at my post in the Caelum Blog – unfortunately – in pt-BR; perhaps, translation tools can help). I have a personal and pragmatic [...]

  3. Integrando Adobe Flex + BlazeDS + SpringFramework + Hibernate - Uma Solução OpenSource para Sistemas Web. (Parte 2 - Final) - Rodrigo Fraga - RIA Evangelist - janeiro 28, 2008

    [...] Perceba que esta classe implementa uma interface, está interface implementa o pattern Repository, este padrão já causou muita polêmica em forums Java como o GUJ por exemplo, recomendo a leitura deste post para entender o padrão: http://blog.caelum.com.br/2007/06/09/repository-seu-modelo-mais-orientado-a-objeto/ [...]

  4. Apollo-Ti Blog - Aborda tecnologias novas para desenvolvimento de softwares - janeiro 29, 2008

    [...] http://blog.caelum.com.br/2007/06/09/repository-seu-modelo-mais-orientado-a-objeto/ [...]

  5. Integrando Adobe Flex + BlazeDS + SpringFramework + Hibernate - Uma Solução OpenSource para Sistemas Web. - julho 16, 2008

    [...] Perceba que esta classe implementa uma interface, está interface implementa o pattern Repository, este padrão já causou muita polêmica em forums Java como o GUJ por exemplo, recomendo a leitura deste post para entender o padrão: http://blog.caelum.com.br/2007/06/09/repository-seu-modelo-mais-orientado-a-objeto/ [...]

  6. Integrando Adobe Flex + BlazeDS + SpringFramework + Hibernate - Uma Solução OpenSource para Sistemas Web. (Parte 2 - Final) - Rodrigo Fraga on Flex and Java - janeiro 13, 2009

    [...] Perceba que esta classe implementa uma interface, está interface implementa o pattern Repository, este padrão já causou muita polêmica em forums Java como o GUJ por exemplo, recomendo a leitura deste post para entender o padrão: http://blog.caelum.com.br/2007/06/09/repository-seu-modelo-mais-orientado-a-objeto/ [...]

  7. Como gerenciar a dependência entre entidades e repositórios? – Mauricio Aniche - outubro 2, 2009

    [...] é um assunto onde há sempre mais um “ponto” a acrescentar. Motivados pelo excelente post da Caelum e discussão do GUJ (onde ambos não são tão recentes assim), eu e o Eduardo Amuri discutimos [...]

  8. Vazamento de memória e de conexões | blog.caelum.com.br - fevereiro 24, 2010

    [...] estava injetada em objetos de modelo na sessao web. Isto é, são sessões usadas pelos nossos Repositories, que faz todo o sentido para o projeto e não é um memory leak, pois a sessão que era [...]

  9. Como gerenciar a dependência entre entidades e repositórios? » Mauricio Aniche - março 31, 2010

    [...] é um assunto onde há sempre mais um “ponto” a acrescentar. Motivados pelo excelente post da Caelum e discussão do GUJ (onde ambos não são tão recentes assim), eu e o Eduardo Amuri discutimos [...]

  10. Dúvida de Design Agreggates e Repository « Pedro Oliveira Blog - março 31, 2010

    [...] Eu achei os seguintes links relacionados ao assunto mas ainda não adotei uma solução. Estou pensando nos pontos positivos e negativos de cada uma das opções. Component Aggregates About Repositories Comments to Gavin King about DDD and Repositories Repository Pattern vs. Transparent Persistence Repository: seu modelo mais Orientado a Objeto [...]

  11. SubMundo Java » Injetando Repositorios (Repository) em entidades de maneira transparente com Spring - abril 4, 2010

    [...] Para saber mais a respeito do conceito por trás desta solução, leia este POST [...]

  12. Código expressivo e programação funcional em Java com LambdaJ | blog.caelum.com.br - fevereiro 13, 2012

    [...] um BO para alterar o VO e persistir usando o DAO no MYSQL ou “salvar cliente  no repositório de cadastros“? Compartilhar [...]

Deixar uma Resposta