Modelo Anêmico é realmente ruim?

Acho que existe muita confusão sobre persistência de objetos.

Na boa, salvem no banco na melhor hora possivel, no lugar aonde fizer mais sentido.

Por exemplo, salvar muitas vezes envolve transações (com direito a rollback, commit, etc). As regras de negocio estão atreladas à persistencia? Acho que deve ser visto cada caso com critica, nem sempre precisamos (ou podemos) ser 100% OO.

[quote=peczenyj]Acho que existe muita confusão sobre persistência de objetos.

Na boa, salvem no banco na melhor hora possivel, no lugar aonde fizer mais sentido.

Por exemplo, salvar muitas vezes envolve transações (com direito a rollback, commit, etc). As regras de negocio estão atreladas à persistencia? Acho que deve ser visto cada caso com critica, nem sempre precisamos (ou podemos) ser 100% OO.[/quote]

Mas seguindo este modelo OO, como seria a melhor solução para isso?

Eu entendi os outros conceitos, mas ainda me sinto perdido com relação a persistência.

O modelo rico me parece muito “bonito de se ver”, mas dificil de se implementar… É como o comunismo… belo de se ler mas dificil de ver funcionar

Bom, eu vou falar como EU costumo fazer. não sei se é o certo, e nem sei se exite um certo e um errado nessa história.

Eu teria meu dominio da seguinte maneira mais ou menos. não exatamente com esses nomes, vou usar eles apenas para deixar o conceito mais claro

Conta
Transferencia
ContaRepositório
TransferenciaRepositorio

Vc reparou que os repositório fazem parte do dominio? como assim? eles não são parte da camada de persistencia?

Não. Eles também fazem parte do dominio. e objetos de dominio podem conversar entre si livremente para implementar regras de negócio.

a classe transferencia poderia receber uma referencia ao repositório de contas, e ao final da operação, inserir estas contas no repositório para que sejam persistidas.

algo como

public class Transferencia{

ContrasRepositoriio contasRepo;

//A transferencia tem uma dependencia do repositório de contas, 
// aqui vc usar seu motor de injeção de dependencias favorito, guice, pico, spring, sei lá
public Transferencia(ContasRepositorio repo){
this.contasRepo = repo;
}

//Este método deve ser transacionado,
public transferirDinheiro(Conta aCreditar, Conta aDebitar, BigDecimal valor){
aDebitar.saque(valor);
aCreditar.depoisto(valor);

//E agora? agora vamos persistir as duas contas para "efetivar" a transferência.
this.contasRepo.save(aCreditar);
this.contasRepo.save(aDebitar);
}

}

Este código no mundo real naõ faria apenas essas operações, a transferencia teria atributos para guardar quais as contas, qual o valor, horario e etc.
A ta, entendi. mas e a transferencia? Vc não precisaria persistir ela pra que ela possa aparecer no extrato, por exemplo?

Sim, mas persistir a transferencia é de obrigação de quem a criou. lá após a chamada a transferir(), a transferencia será persistida.

Agora quem cria a transferencia? sei lá. Pode ser uma fachada ou um ServicoFinanceiro, que disponibiliza todas as operações como saque, deposito, transferencia, desde que garantam a atomicidade da operação.

Entendi.

O repositório seria uma abstração do DAO, certo?

Então no caso ali eu poderia ter um ContaDAO ao invés de ContaRepositório?

Valeu pela explicação

Acho que é um problema mais de adaptar-se que de dificuldade de implementação. O que foi discutido até agora, pra mim, é claro como a agua, porque eu aprendi assim, e tenho enormes dificuldades e acho inumeros problemas usando modelos BOLOVO. É a situação inversa da sua. Acho que é mais constume mesmo.

Só lembrando, mais um link interessante sobre o assunto. um ebook com o basico do basico sobre DDD

http://www.infoq.com/minibooks/domain-driven-design-quickly

[quote=Frango]Entendi.

O repositório seria uma abstração do DAO, certo?

Então no caso ali eu poderia ter um ContaDAO ao invés de ContaRepositório?

Valeu pela explicação[/quote]

Então, sim. É que eu considero repositórios e daos coisas distintas.

no meu dao, eu teria métodos como save, listById, ListForCriteria e coisas assim, 100% voltados a persistencia.

no repositório, eu teria uma instancia do dao dentro dele, criaria as queries necessárias pro meu dominio e delegaria para o dao a execução no banco. apesar de aumentar o acoplamento no caso, eu criaria as critérias/hqls dentro do repositorio e só usava o dao pra executar no banco. Se vc tiver usando Spring com HibernateTemplate, nem de dao vc precisaria, já delegava do repositório direto pro HibernateTemplate. Lógico que aumenta o acoplamento com o spring, mas eu gosto de fazer assim. se for com JPA, delegava pro entitymanager e já era.

[quote=mario.fts][quote=Frango]Entendi.

O repositório seria uma abstração do DAO, certo?

Então no caso ali eu poderia ter um ContaDAO ao invés de ContaRepositório?

Valeu pela explicação[/quote]

Então, sim. É que eu considero repositórios e daos coisas distintas.

no meu dao, eu teria métodos como save, listById, ListForCriteria e coisas assim, 100% voltados a persistencia.

no repositório, eu teria uma instancia do dao dentro dele, criaria as queries necessárias pro meu dominio e delegaria para o dao a execução no banco. apesar de aumentar o acoplamento no caso, eu criaria as critérias/hqls dentro do repositorio e só usava o dao pra executar no banco. Se vc tiver usando Spring com HibernateTemplate, nem de dao vc precisaria, já delegava do repositório direto pro HibernateTemplate. Lógico que aumenta o acoplamento com o spring, mas eu gosto de fazer assim. se for com JPA, delegava pro entitymanager e já era.[/quote]

Mesmo assim eu não entendi o porque de usar o Repositório a usar diretamente o DAO…

http://gc.blog.br/2009/01/17/sindrome-de-dao/

Acho que esta é a diferença.

[quote=mario.fts]O Serviço no caso implementa regras de negócio que não fazem parte de nenhum objeto do dominio.

Vou usar um exemplo, o de conta corrente. não é um bom exemplo, vou explicar pq mais a frente, mas didaticamente acho que é válido.

A conta corrente tem o método saca (double valor) e deposita(double valor). Esses métodos estão no objeto conta pq é faz sentido para o dominio, vc depoisita e saca dinheiro da conta, não da contaService ou da ContaBO entende?
[/quote]

Este é exemplo tipico de um sistema acoplado pouco coeso. Na realidade vc não saca nem deposita dinheiro da conta. Vc executa um movimento na conta. Vc tem uma entidade MovimentoConta que tem informação de onde, quando,quanto e porquê o saldo está sendo alterado. O saldo é a soma de todos os movimentos. A conta não tem uma propriedade saldo. ela tem um calculo de saldo.

Exactamente ao contrário. Vc deveria sim ter um objeto Transferencia e um ServiçoDeTrasnferencia
A trasnferencia é um conjunto de MovimentosConta não necessáriamente 2.

Quando faz um DOC e paga uma taxa existem dois movimentos na sua conta, o do dinherio transferido e o da taxa.

num modelo de banco real, vc precisa dessas entidade todas e faria lago como


public class TransferenciaService{

public transferencia (Conta aDebitar, Conta aCreditar, double valor){

      MovimentoConta debita = new MovimentoConta (aDebitar, valor, Movimento.DEBITA);
      MovimentoConta debitaTaxa = new MovimentoConta (aDebitar, taxa, Movimento.DEBITA);
      MovimentoConta credita = new MovimentoConta (aCreditar, valor, Movimento.CREDITA);

      Transferencia trans = new Transferencia(aDebitar,aCreditar, agora());

     trans.add(credita);
     trans.add(debita );
     trans.add(debitaTaxa );

     // persiste tudo 

     daoTrasnferencia.salva(transf);
     daoMov.salva(credita);
     daoMov.salva(debita );
     daoMov.salva(debitaTaxa );

}
}

Vc precisa dos dois. A Transferencia é o “o quê” o Serviço é o decisor de “como”
Eliminar o serviço em detrimento de um objeto de entidade com a capacidade de executar regras de negocio é errado. Não é boa separação de responsabilidade.

Um método importante de trasfeerencia que pertence realmente na trasnferencia é reverse(). Este método cria e devolde uma transferencia ao contrário que estorna a transferencia inicial. O mesmo para o movimentoConta. Este tipo de método é que não pode ser colocar em outro objeto.

:shock:

public transferir (Conta de, Conta para, double valor){ new Transferencia(valor).debitar(de).creditar(para); transferenciaDao.salva(transferencia); }

[quote=sergiotaborda][quote=mario.fts]O Serviço no caso implementa regras de negócio que não fazem parte de nenhum objeto do dominio.

Vou usar um exemplo, o de conta corrente. não é um bom exemplo, vou explicar pq mais a frente, mas didaticamente acho que é válido.

A conta corrente tem o método saca (double valor) e deposita(double valor). Esses métodos estão no objeto conta pq é faz sentido para o dominio, vc depoisita e saca dinheiro da conta, não da contaService ou da ContaBO entende?
[/quote]

Este é exemplo tipico de um sistema acoplado pouco coeso. Na realidade vc não saca nem deposita dinheiro da conta. Vc executa um movimento na conta. Vc tem uma entidade MovimentoConta que tem informação de onde, quando,quanto e porquê o saldo está sendo alterado. O saldo é a soma de todos os movimentos. A conta não tem uma propriedade saldo. ela tem um calculo de saldo.

[/quote]

Concordo com suas observações, na minha modelagem não daria pra imprimir um extrato por exemplo, devido a essa falta da entidade movimento.

Mas eu sei disso. Eu criei o modelo assim pq não era meu foco explicar como funciona o modelo financeiro, e sim se ele deveria criar um serviço, e onde entra a persistencia nisso tudo. Tudo muito ludico, mas a intenção foi essa mesmo. Mas acho que foi o suficiente pro entendimento do problema proposto.

Um ponto interessante é a sua observação que ele deveria criar um serviçotransferencia e um objeto transferencia. Não tinha pensado assim diretamente, mas cheguei a citar isso no meu texto, na parte que falo do facade e do servicoFinanceiro.

[quote=mario.fts][quote=sergiotaborda][quote=mario.fts]O Serviço no caso implementa regras de negócio que não fazem parte de nenhum objeto do dominio.

Vou usar um exemplo, o de conta corrente. não é um bom exemplo, vou explicar pq mais a frente, mas didaticamente acho que é válido.

A conta corrente tem o método saca (double valor) e deposita(double valor). Esses métodos estão no objeto conta pq é faz sentido para o dominio, vc depoisita e saca dinheiro da conta, não da contaService ou da ContaBO entende?
[/quote]

Este é exemplo tipico de um sistema acoplado pouco coeso. Na realidade vc não saca nem deposita dinheiro da conta. Vc executa um movimento na conta. Vc tem uma entidade MovimentoConta que tem informação de onde, quando,quanto e porquê o saldo está sendo alterado. O saldo é a soma de todos os movimentos. A conta não tem uma propriedade saldo. ela tem um calculo de saldo.

[/quote]

Concordo com suas observações, na minha modelagem não daria pra imprimir um extrato por exemplo, devido a essa falta da entidade movimento.

Mas eu sei disso. Eu criei o modelo assim pq não era meu foco explicar como funciona o modelo financeiro, e sim se ele deveria criar um serviço, e onde entra a persistencia nisso tudo. Tudo muito ludico, mas a intenção foi essa mesmo. Mas acho que foi o suficiente pro entendimento do problema proposto.
[/quote]

Talvez seja isto que está faltando :compreender que a modelagem das classes de dominio depende do dominio.Não se trata de fazer escolhas tecnologias e sim de modelar corretamente. é pela modelagem correta que chegamos a um modelo coeso, desacoplado e não anémico.

As pessoas criam modelo anêmico ou pouco coesos porque:

  1. não entendem o dominio ( analise de requisitos/dominio)
  2. não sabem refletir o dominio em objetos (analise orientada a objetos)
  3. não sabem como devem ser as interações entre objetos ( ponto de vista teorico de OO, padrões, melhores práticas, etc…)

[quote=bobmoe][quote=sergiotaborda]


public class TransferenciaService{

public transferencia (Conta aDebitar, Conta aCreditar, double valor){

      MovimentoConta debita = new MovimentoConta (aDebitar, valor, Movimento.DEBITA);
      MovimentoConta debitaTaxa = new MovimentoConta (aDebitar, taxa, Movimento.DEBITA);
      MovimentoConta credita = new MovimentoConta (aCreditar, valor, Movimento.CREDITA);

      Transferencia trans = new Transferencia(aDebitar,aCreditar, agora());

     trans.add(credita);
     trans.add(debita );
     trans.add(debitaTaxa );

     // persiste tudo 

     daoTrasnferencia.salva(transf);
     daoMov.salva(credita);
     daoMov.salva(debita );
     daoMov.salva(debitaTaxa );

}
}

[/quote]
:shock:

public transferir (Conta de, Conta para, double valor){ new Transferencia(valor).debitar(de).creditar(para); transferenciaDao.salva(transferencia); }
[/quote]

O seu codigo mostra que existe uma entidade MovimentoConta ?
então como vc acha que o seu código é exemplo do que eu disse ?

Não se trata de fluencia aqui e sim de entender o dominio e porquê o objeto transferencia é necessário: para agrupar Movimentos.