O que usar no lugar de VOs?

Ok, então continuamos no mesmo lugar.
O framework (que age como factory) para produzir uma instância do objeto pode ou chamar o construtor sem parâmetros que faz o objeto nascer insconsistente, mas logo em seguida vários setters são chamados pelo framework de forma que ele saia do framework consistente.

Ou então o framework chama o construtor passando um caminhão de parâmetros.

Não. A Fatory substitui a chamada ao construtor, obviamente que ela chama o construtor mas exceto pelas factories ninguém mais o faz. Quando precisa de um objeto dessa classe os outros usam factories. Dessa orma voc6e nucna vai ter objetos inválidos.

De qualquer modo, o que o artigo fala não é sobre invariante na cosntrução do objeto e sim pré/pós condições de um método.

O próprio uso do DAO já não seria um problema ? pois o DAO iria ser um fantoche manipulando as informações do banco de dados.

DAO Não é objeto de negócio então aidna que seja rpeferível que ele seja um objeto ‘de verdade’ acho que não é o maior problema e não o for. De qualquer modo o DAO não é um fantoche, ele é um conversor que pega uma estrutura de dados (i.e. resultsets) e transforma em outras (i.e. objetos de negócio)

Sobre o artigo (é você o autor ou você só publicou?), o que eu me referia mesmo era acerca do parágrafo sobre o encapsulamento.


Ok, mas dentro do método da factory, por alguns nanosegundos após o construtor ter rodado o objeto está em estado inválido, não? Pergunto isso porque dependendo do tipo de verificação de consistência que for feito no objeto de negócio, ela pode fazer a factory falhar lançando alguma exceção (exemplo: IllegalStateException) pelo simples fato de o objeto nascer inconsistente, mesmo que ele fosse ficar neste estado por menos de um milisegundo.

E outra, isso ainda me força ter setters burros para serem usados pela factory?

[quote=victorwss]
Sobre o artigo (é você o autor ou você só publicou?), [/quote]

é meu mesmo

eu também

Sim, mas isso Não é relevante. Se você não utilizar código sincronizado num construtor é muito fácil fazer um objeto ficar em estado inválido, basta preemptar thread atual e chamar o objeto em outra thread. Da mesma forma você pode tornar o código que isntancia o objeto via factory thread safe.

Se a fração de segundo que o objeto fica em estado inválido é importante paravocê então seja com factories ou diretamente com construtores você tem que utilizar código thread safe.

[quote=victorwss]
E outra, isso ainda me força ter setters burros para serem usados pela factory?[/quote]

Acho que não entendi exatamente o que você está chamando de objetos burros, ou não entendi a pergunta. Pode elaborar?

Sobre a parte do synchronized, ok. Acho que isso deve resolver.

Os setters burros, são setters que não fazem nada mais além de repassar o valor para o atributo. Assim como getters burros nada mais são do que getters que simplesmente retornam o valor do atributo.

Não há nada de errado com o getter burro, mas ter setters burros é ruim pois facilmente o objeto entra em estado inválido.

É óbvio que um setter vai verificar os parâmetros e tal para certificar-se que o objeto não entra em estado inconsistente. O problema é quando, por exemplo, para ser consistente deve-se ter ambos o UF e a cidade ou então nenhum deles.
Quando a factory invocar o método setUF, ele vai ver que a cidade é nula e lançar uma exceção, o que faz com que o objeto não possa ser corretamente fabricado. Por outro lado se o método setUF não fizer a verificação, nada garante que o método setCidade seja chamado posteriormente, o que pode deixar o objeto inconsistente.

Outro problema de ter tais setters é que por exemplo: Eu não quero que o atributo X possa ser alterado fora da minha classe de negócio (mas dentro sim). Vamos supor que esse atributo X corresponde a um campo vindo de uma tupla no banco de dados. Só que o problema é que para a factory poder setar este campo, eu tenho que ter um método público setX que não é bem-vindo. Esse tipo de problema o friend do C++ ou algum outro tipo de visibilidade mais fine-tuned que existe em outras linguagens resolveria, mas e no java como fica?

Ok, você está usando o seu TO ou DTO para fazer course-grained RPC. Isso não é procedural também?

Isso é onde eu queria chegar. O DAO também funciona como o cerne do mecanismo de persistencia, como vc mesmo disse, ele pode pegar uma estrutura de dados (i.e. resultsets)e transformar em outras (i.e. objetos de negócio). Porem existe um problema que eu não consigo abstrair completamente: Como definir o objeto de negócio ?

Lendo os conceitos no artigo, e no próprio livro do DDD, o objeto de negocio é algo claro de se entender no mundo real mas dificil de por em prática de uma forma não procedural. Analizando os conceitos do DAO e implementando este no meu código eu me sinto como na dita frase Bad Smell: Você olha, cheira, vê que tem algo errado, e tem que descobrir a causa.

O cheiro ruim é devido ao DAO fazer todo o encapsulamento de persistencia, tirando essa lógica do objeto de negócio. Portanto… para persistir um crédito na conta corrente de um cliente eu preciso recorrer aos mecanismos do DAO pois este processo envolve uma série de transações com outros objetos de negocio.

Adotando o processo acima eu acabo criando outro problema, pois no conceito do DAO, este pode somente manipular um objeto de negocio, ou seja, um DAO para cada tabela no banco de dados, e consequentemente para cada POJO

Portanto para resolver esse problema começamos a usar os chamados BO, este por sua vez pode fazer uso de quantos DAOs forem necessários, pois para persistir um crédito na conta corrente do cliente, é necessário remanejar mais que um objeto de negócio.

Fazendo isso nós caimos no chamado modelo anêmico do Fowler, o que irá nos trazer mais problemas e voltamos ao tópico inicial: Como evitar tudo isso ?

A solução seria colocar a nossa lógica de nogócio nos objetos de negócio, e isso parace muito claro. Mas ao fazer isso nos encontramos os já conhecidos problemas da persistencia e do controle da transação. Mesmo assim algumas pessoas começaram a fazer isso:

Fornecedor fornecedor = ?; List contas = fornecedor.getContasPagasDesde1999()
Sim, por tráz das cenas o método getContasPagasDesde1999() irá usar um repositório, e esse repositório pode ser a implementação de um DAO, e sinceramente ainda sinto um Bad Smell :? pois acredito que seja possível fazer isso com C e por favor me corrijam se estiver errado pois eu conheço pouco de C.

Você está chegando aonde eu quero chegar também. O que nos empurra a um modelo anêmico é o DAO e o problema de evitar o modelo anêmico começa a se reduzir a evitar que o DAO seja intimamente acoplado ao objeto de negócio.

O único lugar que você falou besteira foi na parte de programar em C. C faz tudo e qualquer coisa. As partes do java que não foram feitas no próprio java são feitas em C e C++, e um dos grandes problemas do C é justamente este, nada te impede de fazer cagada. Mas isso já está offtopic.

Desculpa não ter mencionado, mas a referência que eu faço ao C é a mesma sobre o artigo do Fantoche.
Vou tentar lhe poupar tempo com o texto a seguir e esclarecer um pouco o porque da referencia ao C, mas também peço que leia o artigo novamente e com mais atenção.

Se vc esta fazendo um programa em java para controlar um estacionamento, como no exemplo do artigo, e por acaso vc também consiga fazer o mesmo programa em C e ver que a maior diferença esta na mais fútil convenção de nomenclatura, então irá perceber que existe alguma coisa errada.

Dito a frase acima, pense: Se o C que é uma linguagem procedural consegue fazer a mesma coisa que eu numa linguagem orientada a objetos é porque existe alguma coisa de errada, e com certeza não é a linguagem, e sim a forma de como vc esta escrevendo os seus programas.

Simples. Chame DAO ao BO e chame TableGateway ao DAO.

O ponto é que DAO não é aquilo que normalmente se vê por ai. Um DAO por entidade é um design furado e por isso tem todos esses problemas. No fim vc precisa de um orquestador para multiplos dao.
Entenda que vc sempre deve ter esse orquestador, pois é o logico. Chame de BO, Repositorio ou qq outra coisa, o fato é que vc quer persistir um objeto complexo que se espande por multiplas tabelas.
A função do DAO é converter comandos java em comandos SQL e isso deve ser feito por meio de mecanismos abstractos.

Enfim, vc precisa de um design mais poderoso e afinado se quer ter persistencia inteligente.

[quote=ronildobraga]O cheiro ruim é devido ao DAO fazer todo o encapsulamento de persistencia, tirando essa lógica do objeto de negócio. Portanto… para persistir um crédito na conta corrente de um cliente eu preciso recorrer aos mecanismos do DAO pois este processo envolve uma série de transações com outros objetos de negocio.
[/quote]

Acho que você não está levando em consideração uma coisa muito importante: persistência é um cocneito ortogonal a negócio. "Persistir uma C/C"não é regra de negócio, é limitação tecnológica. O DAO e seus amios servem para ajudar a contornar os problemas causados por essa limitação.

O que você precisa fazer é executar a regra de negócio apenas com objetos e persistir o estado final. Voc6e executa a regra de negócio e depois “aperta o botão salvar”. Até você “apertar o botão” nada de persistência é envolvido (não diretamente).

Como você usa os objetos que fazem as regras não depende de existir um objeto burro ou inteligente -se o DAO cospe estruturas de dados ou objetos. Isso, como falei, é ortogonal.

Você pode fazer isso com C(com adaptações) e isso não é problema. O problema é programar em java comos e programa em C e não programar em C como se programa em Java.

O Repositorio existe exatamente para abstrair a existência de um DAO do modelo de negócios. Ainda não entendi porque um DAO acarretaria em BO/TO.

Sim, quanto a esse negócio de utilizar um DAO por tabela, isso só funciona para CRUDs simples. O DAO deve utilizar várias tabelas. e criar objetos de negócio cujas regras podem estar em várias tabelas. Até aqui ok.

O porque do DAO te empurrar para o modelo BO/TO é por causa daqueles setters e getters. O DAO precisa de getters e setters (normalmente burros) no objeto que ele está manipulando. Isso nos leva ao modelo onde a consistência do objeto de negócio poderia ser quebrada facilmente por causa desses setters e getters. Para “resolver” isso, a “solução” seria separar esse objeto em BOs e TOs, ou seja, o modelo anêmico.

O problema aqui é que é preciso alguma outra estratégia para fazer o DAO poder acessar os dados internos do objeto de negócio enquanto este está sendo criado. Ou seja, volto ao que coloquei no meu post anterior:

E então, no java como fica?

Meu palpite é que exigir “cidade e UF ou nenhum deles” sendo estes campos independentes no POJO é um bad smell por si só.

A outra sugestão é fazer o setter garantir o estado válido (lançando IllegalStateException) e fazer a ferramenta de ORM preencher os valores via reflection.

[quote=victorwss]
O porque do DAO te empurrar para o modelo BO/TO é por causa daqueles setters e getters. O DAO precisa de getters e setters (normalmente burros) no objeto que ele está manipulando. Isso nos leva ao modelo onde a consistência do objeto de negócio poderia ser quebrada facilmente por causa desses setters e getters. Para “resolver” isso, a “solução” seria separar esse objeto em BOs e TOs, ou seja, o modelo anêmico.

O problema aqui é que é preciso alguma outra estratégia para fazer o DAO poder acessar os dados internos do objeto de negócio enquanto este está sendo criado.[/quote]

Um objecto persistivel, embora não seja essa a prespectiva normal, é uma implementação do padrão memento.
É preciso entender que o objeto tem atributos e metodos, mas não tem dados. Os dados são coisas que são introduzidas (injetadas/ settadas) no objeto. à partida um objeto de qq classe permite qq valor nos seus atributos.
Se o objeto está sendo populado pelo DAO os dados no banco já foram validados antes. (tudo bem que os dados no banco podem mudar “sozinhos” mas isso é uma porcaria de arquitetura)
O ciclo de vida de um objeto persistivel é
antes de ser persistido : criada (vazio) , preenchido (pela aplicação) , persistido.
depos de ser persistido : criado (vazio) , preenchido (pelo sistema de persistencia) , retornado à aplicação , alterado , persistido.

O uso de get e set é diferente se foi usado pelo DAO ou pela aplicação.
Vc pode colocar logicas especias de controle de consistencia de estado no seus setters para que quando o programador preenche o objeto na aplicação erros possam ser interceptados. E nesta caso o DAO tem que setar os campos sem usar os setters (setando directamente os atributos).
Em alternativa vc pode ter setter sem nenhuma consistencia e colocar essas regras num objeto especifico para isso. Um objeto de especificação. Esse objeto é usado para validar o objeto como um todo. No caso do UF e da cidade pode haver casos em que isso é um erro e casos em que não. Colocar a logica de consistencia num objeto à parte permite não só um bom SoC mas tb implementar várias regras para o mesmo objeto em contextos diferentes.

Então o objeto fica burro ? Não. Inteligencia não é validar consistencia.
Inteligencia é prover métodos que sejam uteis a quem usa o objeto. Ou seja, é introduzir métodos auxiliares
O exemplo tipico é a idade. Existe um método idade(Date day). Isto não é um campo , nem um atributo. É uma regra da entidade. Pessoas têm idades, mas elas são calculadas, são dinamicas. Dependem da data em que se fizer a pergunta. Isto que é inteligencia de um objeto persistivel. Pode haver outras, mas nenhuma será um serviço.
Coisas como contaA.transfere(100, contaB) não são inteligentes. São idiotas. A transferencia em si é uma objeto do dominio que usa contas. Não são as contas que usam transferencias.
Enfim, objetos persistiveis podem ter inteligencia, podem ter regras de dominio e até regras de negocio, mas não podem fazer o sistema todo. Essa é afinal a diferença entre programa em java e em SQL.
Sendo que não podem ser o sistema todo são necessários outros objetos. Isso não é um problema, é a solução.
E esses objetos nem têm que ser todos persistiveis.

vejo q o assunto ja disvirtuou para outra coisa…

mas voltando ao assunto base… e para as views? o que usar para trafegar a informação na view?

Não é porque vocêtem set/get para o DAO que seu modelo é anêmico. O que faz o modelo ser anêmico é ser tratado proceduralmente ao executar regra de negócio, não haver set/get que são utilizados apenas em outra Camadas. Você vai ter esse mesmo problema na Camada de apresentação, que vai precisar de gets.

De qualquer forma, entendo que às vezes a existência de um set numa classe pode trazer problemas. Sugestões:

  1. Padrão memento
  2. Usar uma nterface sem get/set na camada de negócios e sua implementação com get/set na camada de persistência.
  3. azer o DAO criar uma subclasse da classe real que possua set/get

[quote=luistiagos]vejo q o assunto ja disvirtuou para outra coisa…
mas voltando ao assunto base… e para as views? o que usar para trafegar a informação na view?[/quote]Essa questão ja foi respondida na primeira página, segue abaixo resposta.[quote=Paulo Silveira]Perfeito!!! DTO é para trafegar beans entre TIERS, nao entre LAYERS! Entre layers é perfeitamente aceitavel que layers diferentes acessem suas entidades de dominio![/quote] Portanto as entidades de dominio são os seus POJOs, que podem ser trafegados assim como vc fazia para os VOs.

Entendi que o repositorio serve para abstrair o mecanismo de persistencia e que isso é ortogonal. Mas eu digo que o DAO acaba acarretando em um BO porque o DAO não pode ser manuseado exclusivamente pelo POJO.

O exemplo fornecedor.getContasPagasDesde1999() funciona para um problema simples, uma consulta. Quando estamos conversando com o cliente e definimos uma solução para um determinado problema, acabamos por perceber que a lógica dessa solução envolve outros objetos de negócio, portanto quando estamos fazendo a arquiterura do sistema não podemos adicionar essa lógica a um POJO como no exemplo fornecedor.getContasPagasDesde1999().

A solução seria criar um serviço, e se eu entendi bem acho que essa é a abordagem do DDD. Esse serviço irá funcionar como a função mestre citada no artigo do fantoche, o que parece ser um problema.

Na solução do Sergio onde ele disse: No fim vc precisa de um orquestador para multiplos dao. Entenda que vc sempre deve ter esse orquestador, pois é o logico.

Refletindo a frase acima, isso se encaixa no problema dos fantoches, mas me parece lógico para um problema muito comum em um sistema bancário, pois precisamos desse orquestrador com toda a sua lógica para gerenciar difentes contas correntes.

Realmente é um bad smell por si só, mas em certos casos é difícil fugir de coisas assim.
E quanto a acessar direto o campo, isso resolve o problema em alguns casos, mas não em todos (por exemplo, quando eu tenho getters e setters inteligentes, que não acessam o campo diretamente e sim fazem outras coisas como salvar logs, acessar aquivos e criar outros objetos, por qualquer motivo que seja). O exemplo da idade do sergiotaborda é um bom exemplo.

Isso em geral é uma boa idéia. Tende a levar ao memento que o pcalcado citou abaixo. Volto nesse assunto mais abaixo.

Na verdade os getters não são problema, logo não haverá nada de errado com a camada de apresentação.

A alternativa 3 me parece criar mais problemas do que resolver.

A alternativa 2 é legal, apesar que um cast seria o suficiente para quebrá-la. Mas mesmo assim é boa.

A alternativa 1 é boa e funciona. O DAO cria o memento e o manipula como quiser. Daí ele salva o memento no objeto de negócio ou então o joga fora. Quase perfeito, o porém é que esse objeto memento não seria um TO disfarçado? Apesar de que mesmo que seja, o modelo já não é mais o anêmico, pois ao invés de todos usarem o TO, todos usam o objeto de negócio e o memento (TO disfarçado) só serviria para a comunicação com o DAO.