Estou estudando DDD e tentando aplicar conceitos em uma implementação teste e tenho a seguinte dúvida:
Segundo a literatura (Eric Evans), um [b]Value Object/b é um objeto onde o que importa é o seu valor, ou seja, todos os atributos identificam a identidade do objeto e não um único ID como por exemplo Pedido, Pessoa, ou outra [b]Entity/b.
Considerando duas classes simples, Pessoa e Endereço onde no meu entendimento Pessoa é um Entity e Endereço um Value Object (Pois podem 2 pessoas morarem no mesmo endereço e o que identifica o endereço são todos seus atributos), seguem alguns questionamentos:
[list]Após persistido, como eu recupero esse Endereco no banco se não tem um ID ? vou ter que comparar todos os campos na query ?[/list]
[list]Como Value Object teoricamente não tem ID, como na hora de persistir vai ficar registrado no BD que a Pessoa mora naquele Endereco?[/list]
[list]Vou ter que criar uma constraint no Banco com todos os campos para evitar duplicidade de Endereco ? Qual seria uma outra forma de garantir que não serão incluidos 2 Value ObjectsEndereco iguais?[/list]
[list]E no com hibernate como que fica pra recuperar e garantir que não serão incluidos 2 Value ObjectsEndereco iguais já que não tem ID ?[/list]
Pelo que eu tenho lido a respeito e aplicado, o Value Object é recomendado para uso quando vc tem uma aplicação em ambiente distribuido em mais que 1 JVM, pois você recupera um Entity como objeto persistente, o transforma em transiente, usando o VO.
Leia este tutorial que pode te dar uma idéia de como usá-lo, se realmente vc precisar usá-lo.
Opa!
Value Object é um objeto simples nao referenciado… um “agrupado” de atributos que juntos identificam alguma coisa no sistema…
No banco um value object pode ateh ser um type (mas nao sei como ficaria isso pro hibernate, nesse caso uma tabelinha ia bem)… depende do que quer fazer… eu nao definiria endereco como um value object, não acho endereco uma classe assim tao simples… (logradouro ateh q poderia, pq a primeira vista soh teria tipo, descricao e numero)
o lance da constraint para evitar repeticao tmb é um fato… se nao quer q repita vai ter q colocar lah… mas e aih, como fica se cadastrar duas pessoas com o mesmo endereco, vai apontar para o mesmo registro??? nao sei se rola, pq se fizer isso qdo alterar o endereco do primeiro vai alterar o do segundo tmb… fazer o q, enderecos podem repetir…
por essas eu vejo q um id vai bem e endereco nao seria simplificado como um value object…
Primeiro ha que esclarecer a diferença entre VO do DDD e VO fora do DDD.
Value Object é muito usado como sinónimo de DTO (Data Transfer Object) especialmente quando
não se trata de transferencia entre nodos mas apenas entre camadas. Neste significado VO é um objeto relacionado a arquitectura do sistema.
Todo o mundo entendia isto até que o senhor Fowler dicidir usar Value Object para identificar
objecto imutável que contém um valor. Esta categoria de objetos que incluem , por exemplo, String, Number, Date - e outros como Money - e não tem nada a ver com os DTO. Neste significado VO é um objeto relacionado a modelagem.
Em DDD Value Object é entendido com o significado dado por Fowler e não com o significado sinónimo de DTO.
Então é preciso ter muito cuidado quando se fala de Value Object.
O emerleite falou explicitamente dos VO do DDD que são objetos em nada relacionados aos DTO e aos problemas arquitecturais.
dito isto, é preciso esclarecer que o colega emerleite não apanhou completamente o conceito de VO.
Não é bem verdade isto. Aliás é verdadeiramente o inverso.
O VO é um objeto onde o que importa é o seu valor, ou seja, ele não tem identidade.
Em outras palavras VO é o valor que um campo da identidade assume e que não se refere a outra entidade.
Exemplos: nome, datas , quantidades (monetárias ou métricas) , unidades, categorias, codigos (CEP,CNPJ…).
Endereço e um bom exemplo de caso dubio. Como o ppr Evans explica, Endereço será uma entidade se o sistema precisa controlo do endereço de forma independente do resto dos objetos. Num sistema de correio o endereço é a entidade principal. Cada endereço tem que ser identificado no sistema para que a correspondencia possa seguir seu caminho. Num sistema de contas a pagar o endereço do cliente é uma mera informação associada ao cliente ( é um campo de cliente) onde o endereço nunca é tratado de forma separada do cliente a quem pertence.
No primeiro sistema, endereço terá sua tabela propria com chaves e tudo o mais. No segundo, endereço será um conjunto de campos na tabela de cliente, que quando o cliente é lido são aglomerado no objeto diferente
em codigo
public Cliente getClienteById( int ID){
ResultSet rs = dao.executaQueryNativa ("Select * from cliente where cliente_id = ?" , ID);
rs.next();
Cliente c = new Cliente(ID);
c.setNome(rs.getString("nome"));
c.setNascimento( rs.getDate("nascimento"))); // o objeto Date é um VO (padrão java)
c.setCNPJ( new CNPJ(rs.getString("cnpj"))); // o objeto CNPJ é um VO (não-padrão do java)
Endereco ed = new Endereco();
ed.setLogradouro (rs.getString("logradouro"));
ed.setCEP(new CEP(rs.getString("cep"))); // o objeto CEP é um VO (não-padrão do java)
ed.setNumero(rs.getString("numero"));
ed.setComplemento(rs.getString("complemento"));
c.setEndereco(ed);
return c;
}
Não existe tabela endereço, mas existe objeto Endereço. Isso caracteriza um VO. Um VO não precisa de tabela propria (embora possa ter uma). Uma entidade tem que ter uma tabela própria.
Outro exemplo. Pedido e Item. O item não existe sem um pedido e não pode ser transferido entre pedidos.
O item não tem uma identidade per se, ele sempre necessita estar ligado a um pedido. então pedido é uma entidade e item é um VO. Neste caso Item terá a sua propria tabela porque a relação pedido-item é um-para-muitos, mas apenas por isso, e não porque é uma entidade. Em termos de banco o Id do item é composto por um numero + o id do pedido.
Produto p = ...
Item it = new Item (p, 34);
Pedido a = new Pedido();
a.add(it); // ok
Pedido b = new Pedido();
b.add(it); // erro : O item já está associado a outro pedido
// controlo dentro de pedido
public void add (Item item ){
if (item.getPedido()==null){
item.setPedido(this);
listadeItens.add(item);
}
throw new IllegalAgumentException(O item já está associado a outro pedido);
}
Quanto ao problema de duplicar endereços.
Se A e B vivem no mesmo endereço A e B são a mesma pessoa ? não.
Então é possível existir duplicação de endereços e endereço não é uma entidade, é um VO.
Espero que seja mais claro o papel do VO no DDD e sua diferença do VO comum
Marcio, vc se enganou pois o Value Object que estou falando é o catalogado pelo Eric Evans e Martin Fowler que nada tem a ver com o antigo da Sun que já mudou de nome para Transfer Object e Fowler catalogou como Data Transfer Object.
Mas Endereco não seria identificado apenas pelos seus atributos diferente de Pessoa que por um CPF se identifica já que não pode se repetir ?
Eu entendi que se o endereço mudasse já não seria o mesmo Value Object e sim outro, consequentemente quando fosse persistir seria gravado um outro Endereco e apontando pra esse.
Endereco então seria um Entity ? Não consegui ver dessa maneira. Talvez esteja faltando ainda pra mim algum entendimento a mais sobre o assunto. Se alguém puder esclarecer …
Faltou dizer como ficaria o relacionamente entre eles no BD após persistir caso Endereco seja Value Object vc sabe ?
Identificar é diferente de encontrar. CPF não identifica a pessoa. A identidade da pessoa não é convertivel em bytes. Por isso temos subterfurgios como o RG e o CPF. O conceito é que cada CPF é de uma pessoa e cada pessoa tem um CPF, mas esta regra comum é falseável. (um bandido que é uma pessoa tem varios CPF …ou nenhum conforme se veja). Então CPF não identifica a pessoa. RG idem.
Os codigos de identificação podem mudar (CGC -> CPF). Isso não significa que a pessoa mudou.
O que identifica a Pessoa ? O que faz uma pessoa ser diferente de outra pessoa não é o que identifica a pessoa.
O que identifica a pessoa é a pessoa em si. :lol: bom, Identidade é um conceito matemático. Ou se entende ou não se entende.
Não é possivel colocar a identidade em bits , por isso é necessário criar artficios. usar codigos identificadores não é boa ideia. O bom é usar um numero sequencial unico no sistema, não alterável dado no momento em que a pessoa é pela primeira vez "manipulada" pelo sistema. Se esse numero é o mesmo, a pessoa é a mesma. tudo o resto pode mudar. todos os atributos podem mudar, mas a sua identidade nunca mudará.
Claro que uma dos atributos da Pessoa será o CPF, mas ele serve para procurar e encontrar a pessoa e não para a identificar.
O conceito de identidade é muito complexo , e simples ao mesmo tempo e é essencial para entender o que o DDD chama de Entity.
Obrigado pela ajuda mas acho que vocë não entendeu o ponto ou eu não expliquei direito.
[quote=sergiotaborda]Num sistema de contas a pagar o endereço do cliente é uma mera informação associada ao cliente ( é um campo de cliente) onde o endereço nunca é tratado de forma separada do cliente a quem pertence.
No primeiro sistema, endereço terá sua tabela propria com chaves e tudo o mais. No segundo, endereço será um conjunto de campos na tabela de cliente, que quando o cliente é lido são aglomerado no objeto diferente
em codigo [/quote]
O meu caso é justamente o segundo e eu não sabia que mesmo com N pessoas no mesmo endereço eu iria repetir a informação de endereço no BD. Pelo que eu entendi que você falou sim e seriam campos da tabela pessoas. Me entenda que eu estou apenas tentando entender como é a implementaçào na prática e não comparando modelo OO com relacional, mas no fim das contas temos que implementar a persistência disso e então saber como fazer da maneira correta.
Um value object pode ter esse id (que você ta chamando de número) que não serve pra nada ?
Eu acho q o Endereco se enquadra sim no chamado Value Object. Por mais q mais de uma pessoa possa morar no mesmo endereco ele continua sendo uma informacao unica a entidade. Um endereco solto (claro q isso dependendo da abordagem e da finalidade do que se esta fazendo) um endereco solto nao faz sentido algum.
Agora na pratica, pelo menos o hibernate normalmente trata o VO como “component”. Todas as informacoes sao mapeadas para a mesma tabela. Por ex: A tabela cliente vai ter o Id, nome, cpf etc, e mais o campos do objeto Endereco.
Não. Não pode. Se tiver ele passa a ser uma Entity.
Se o seu caso é aquele em que os campos relativos a endereço estão no mesmo registro que os de cliente, então eu já exemplifiquei como implementa. Vc lê todos os campos de uma vez e depois divide em objectos vai incorporando no objeto Cliente. Quando for gravar , vc faz o contrário, lê todos os campos , inclusive os do objecto endereço e joga na mesma frase do updade. A chave do update será o ID do cliente. Vc nunca precisará de um ID para o endereço.
Como disse, Identidade não é conversível em bytes, nem em papel , nem em nada.
Por isso vc tentar identificar a pessoa com marcadores que supostamente são unicos como impressão digital, retina , veias no dedo , DNA ou o CPF …
Entenda que tudo isso são attributos da pessoa e não representam a pessoa em si, portanto não são a identidade da pessoa, são apenas marcadores únicos.
A prova de que a identidade não está no CPF é que os bandidos têm vários
CPF é uma chave lógica q foi inventada para simplificar a identificacao de pessoas, assim como o CEP para enderecos.
Eh interessante reconhecer a chave natural de uma entidade(no caso do endereço foi visto q a chave natural envolveria todos os campos), decidir fazer dela uma chave unica já é um outro passo…
Usar um identificador significa trocar a equivalente chave natural por uma logica, que pode ser uma padronizada (CPF, CEP, RG, etc) ou um ID do sistema (um sequencial da vida) para identificar um determinado registro e evitar repeti-lo.
Tah, mas e aih, no caso do endereco, de que isso me interessa? se a relacao entre pessoa e endereco é de 1 para 1, nada… Pessoa entao deve ter os atributos de endereco
Se a relacao eh de um pra muitos… aih comeca a importar, pois terei q buscar os enderecos de alguma forma e identifica-los (seja por chave natural ou logica). Se eu preciso dizer no sistema quais os enderecos de uma determinada pessoa nao vou querer passar todos os campos do endereco pra isso, a chave logica vai bem…
Se a relacao é de muitos pra muitos aih tem q pensar no problema de enderecos orfaos… de alterar um endereco de alguem e por consequencia de outra pessoa relacionada 'aquele endereco, tem quem faca disso um motivo para chave primaria composta no banco e mais um monte de problemas…
Enfim… eu prefiro repetir enderecos… uma pessoa um endereco… ou, se necessario, uma pessoa muitos enderecos.
Qdo disse que endereco nao é uma classe simples foi por ter muitos atributos, tipo de logradouro (rua, av., etc) , descricao, numero, complemento, cep, cidade, estado…
É viajem ficar imaginando alguma operacao pra essa classe, nao conheco o seu sistema e nunca usei nenhuma operacao relacionada ao endereco (receberPostagem ou algo do tipo) cabe a voce saber se pode ter alguma coisa do tipo… se tiver, esquece VO (mas como fez o dever de casa e eu acho q entendeu sim o conceito de VO jah deve saber disso)
Se voce fizer do endereco um VO vai estar atrapalhando o encapsulamento de Pessoa ??? divindo atributos q sao da pessoa com uma classe Endereco… O que voce ganha fazendo de Endereco um VO? VO = TIPO
Eu entendi mas isso contradiz um pouco o que vê disse no post anterior dizendo que Item era um VO mas que item tinha um ID
Ok isso eu sei mas o importante era saber se ia duplicar o endereço. Pelo que eu entendi duplica. Obrigado
Ok mas dentro de um domínio de um sistema, Uma entidade de uma pessoa fisica pode sempre ser identificada pelo CPF que é unico e nesse caso o que impede do CPF ser a identidade da pessoa ?
Eu entendi mas isso contradiz um pouco o que vê disse no post anterior dizendo que Item era um VO mas que item tinha um ID
[/quote]
Eu disse "Em termos de banco o Id do item é composto por um numero + o id do pedido. "
Ou seja, no banco vc vai ter uma coluna chamada “numero” e outra chamada “pedido_id” e os dois são a chave (o id em termos de banco) do VO no banco.
Em objetos o VO não terá informação do ID do pedido e sim uma referencia ao objeto Pedido. O VO terá internamente o attributo “numero” mas ele será imutável. Nada disto caracteriza a identidade do VO.
A coluna “numero” a que me referi no texto original era para fornecer um mecanismo de IDENDITDADE, esta coluna “numero” a que me refiro aqui é um mecanismo de CONSISTENCIA só para que ao gravar o item de volta vc possa fazer um update e não um insert. São coisas diferentes. Vc perguntou se o “numero” para fornecer identidade poderia ser usado no VO, a reposta é “não” porque eles não servem o mesmo objetivo.
[adicionado]
A diferença é na hora de implementar equals
Item.equals(item) sse todos os campos são os mesmos e não se idpedido+numero é igual
Uma entidade terá um método isSameAs() que compara o numero de IDENDITDADE apenas.
[adicionado]
Pense um momento: ‘A’ e ‘A’ são duas representações da mesma coisa, ou são a mesma coisa representada duas vezes ?
.
.
.
Se são duas representações da mesma coisas, então ‘A’ é um valor.
Se são a mesma coisas representada duas vesez , então ‘A’ é uma entidade
“Rua do Aroche , 10 apt 90” e “Rua do Aroche , 10 apt 90” são são das hipoteses ? 8)
A minha dúvida sempre foi no Banco por isso que eu perguntei como que fica no Banco. Um VO não teria ID mas eu havia entendido que na hora de persistir no caso do Item haveria um ID no banco para poder relacionar com o Pedido.
Isso é basico em OO e eu sei. A questão é só na hora de persistir
[quote=sergiotaborda]Pense um momento: ‘A’ e ‘A’ são duas representações da mesma coisa, ou são a mesma coisa representada duas vezes ?
.
.
.
Se são duas representações da mesma coisas, então ‘A’ é um valor.
Se são a mesma coisas representada duas vesez , então ‘A’ é uma entidade
“Rua do Aroche , 10 apt 90” e “Rua do Aroche , 10 apt 90” são são das hipoteses ?[/quote]
Concordo. Novamente a questão é na hora de persistir se seria correto duplicar o mesmo endereço sendo que uma mesma pessoa pode morar naquele endereço. Pelo que eu entendi devemos duplicar. Valeu pelo esclarecimento.
Estou aproveitando este tópico antigo para não criar um novo.
Gente, como se trata um Value Object (DDD, catalogado por Fowler e Evans) num mapeamento de hibernate?
Ah, poderíamos tomar como base os exemplos de value object do Shoes na revista Mundo Java 17(OO com padrões de negócio). Como ficaria o Value Object Categoria e o Moeda num mapeamento de Hibernate e no banco de dados?
[quote=emerleite]
[list]Após persistido, como eu recupero esse Endereco no banco se não tem um ID ? vou ter que comparar todos os campos na query ?[/list]
[list]Como Value Object teoricamente não tem ID, como na hora de persistir vai ficar registrado no BD que a Pessoa mora naquele Endereco?[/list]
[list]Vou ter que criar uma constraint no Banco com todos os campos para evitar duplicidade de Endereco ? Qual seria uma outra forma de garantir que não serão incluidos 2 Value ObjectsEndereco iguais?[/list]
[list]E no com hibernate como que fica pra recuperar e garantir que não serão incluidos 2 Value ObjectsEndereco iguais já que não tem ID ?[/list][/quote]
Acho que o problema aqui é de mapeamento objeto-relacional. Domain-Driven Design fala sobre como seus objetos são definidos, não sobre como representá-los em tabelas e bancos de dados. No seu caso específico se no modelo relacional o Value Object tem ou não ID não é um problema -diretamente- relacionado a modelagem de objetos, logo não é um aspecto de DDD.
Correto, por isso o título da pergunta está relacionado a persistência do Value Object e não no seu conceito. Porém, parece que eu ainda não entendi alguma coisa …
Eu achava que um ID caracterizaria a Identidade o tornando uma Entity, mas devo ter entendido errado. Poderia me explicar onde estou fazendo a confusão toda ?
Correto, por isso o título da pergunta está relacionado a persistência do Value Object e não no seu conceito. Porém, parece que eu ainda não entendi alguma coisa …
Eu achava que um ID caracterizaria a Identidade o tornando uma Entity, mas devo ter entendido errado. Poderia me explicar onde estou fazendo a confusão toda ?
Abs …[/quote]
Cara não sei se você já chegou à um entendimento, mas a questão é a mistura que você está fazendo entre a persistência e o domínio. No seu domínio, o objeto XPTO vai ser um Value Object, porém, do ponto de vista da persistência, você vai precisar de um Id (considerando esse caso), mas note bem, o ID é necessário apenas do ponto de vista da persistência, não do ponto de vista do seu domínio, logo, para o seu domínio, ele não é um Entity.