Modelagem PessoaFisica,PessoaJuridica,Cliente usando Hibernate

Olá pessoal,

Está é mais uma dúvida sobre uma assunto que já é antiga aqui no fórum visto pelo número de postagens sobre o assunto. No entanto mesmo lendo estes posts eu ainda fiquei com dúvida. Então gostaria de uma ajuda de vocês que entedem bem sobre o assunto.

A minha dúvida inicial era sobre como modelar uma Classe de Cliente, sendo que o cliente pode ser uma Pessoa Física ou Jurídica. Agora eu tenho modelado da forma que acredito ser suficiente.

Modelagem das classes:

  1. Criei uma Classe Abstract para Pessoa: public abstract class Pessoa
  2. Criei uma SubClasse para PessoaFisica: public class PessoaFisica extends Pessoa
  3. Criei uma SubClasse para PessoaJuridica: public class PessoaJuridica extends Pessoa
  4. Criei uma Classe para Cliente (composição)


public class Cliente {
private Pessoa pessoa;

public setPessoa(Pessoa pessoa)…
public Pessoa getPessoa();

}

Ai idéia era simples, sendo a classe Pessoa Abastract eu era forçado a instanciar usando a Classe PessoaFisica ou Juridica conforme o tipo do cliente e quando eu precise pegar os dados inerente a uma PessoaFisica ou PessoaJuridica eu simplesmente faria um Cast conforme o tipo do cliente.

Mas aqui está a duvida como fazer o Mapping do hibernate nesta situação via XML?

No banco de dados existem 4 tabelas diferentes:
Uma Para Pessoa (PK CodigoPessoa)
Uma Para PessoaJuridica (PK CodigoPessoa FK com CodigoPessoa)
Uma Para PessoaFisica (PK CodigoPessoa FK com CodigoPessoa)
Uma Para Cliente (PK CodigoPessoa FK com CodigoPessoa)

O Configuração da Pessoa.hbm.xml tá feita e funcionando, o problema esta em como mapear o attributo pessoa da classe Cliente para que o mesmo funcione quando eu for dar um load, ou seja, instancie a Classe correta conforme o tipo do cliente (PF ou PJ).

Pessoal, vocês acham que está forma acima é viagem, tá tudo furado o conceito?

Obrigado pela atenção

cara você conhece bem o conceito de herança ?

como assim, subclasse sem herança ??

Conheco sim!, :D, dei um Ctrl+C e Ctrl+V e acabei esquecendo de mudar, foi mau.

A frase “Criei um SubClasse Cliente (não é herança)” está errada.

Já editei o post e corrigi, somente para reiterar, a classe Cliente é uma composição de uma Pessoa.

Obrigado pelo aviso,

Olá
Só uma dúvida: há realmente a necessidade de usar composição na relação Cliente - Pessoa? Acho que só seria preciso fazer dessa forma se você fosse mudar a pessoa associada ao Cliente em tempo de execução… Seguindo a lógica, um cliente É - e não TEM - uma pessoa. Acho que você tá levando a regra da composição ao pé da letra demais.
Segue uma sugestão de implementação, que permite você determinar dinamicamente se uma pessoa será física ou jurídica:

[code]public interface CadastroNacional {
// Nas subclasses, você pode lançar um IllegalArgumentException se o cpf ou cnpj não for válido
public void validar();
}

public class CPF implements CadastroNacional {
private String cpf;

public CPF(String cpf) {
	this.cpf = cpf;

	validar();
}

public void validar() {
	// Código de validação de CPF
}

public String toString() {
	// Sobrescrevendo o método toString para formatar o cpf de forma adequada
}

}

public class CNPJ implements CadastroNacional {
private String cnpj;

public CNPJ(String cnpj) {
	this.cnpj = cnpj;

	validar();
}

public void validar() {
	// Código de validação de CNPJ
}

public String toString() {
	// Sobrescrevendo o método toString para formatar o cnpj de forma adequada
}

}

// Note que esta classe não é abstrata
public class Pessoa {
// Olha a composição aqui
private CadastroNacional cadastro;

public void setCadastroNacional(CadastroNacional cn) {
	// Aqui você pode passar um objeto do tipo CPF ou CNPJ
}

}

// Você ainda precisa da classe Cliente? Se sim, aqui vai:
public class Cliente extends Pessoa {

}
[/code]Se você preferir, pode fazer CadastroNacional uma classe abstrata em vez de uma interface.
Abraços

Você realmente precisa dessa hierarquia toda? O exemplo de Pessoa como suerclasse de Pessoa Jurdica e Fisica é muito utilizado mas é um dos exemlos mais infelizes que existem. Acho que a solução do tnaires é razoável mas eu rocaria toda a complexidade por apenas uma classe e um Strategy no validador, creio.

Mas como, por exemplo, eu conseguirei atribuir um endereço a uma pessoa.

Uma pessoa, pode ter vários endereços.

E um endereço pode ser de uma pessoa fisica, ou juridica …

Nesse caso, justifica-se a herança de Pessoa -> Pessoa Fisica | Pessoa Juridica

[quote=_filipe]Mas como, por exemplo, eu conseguirei atribuir um endereço a uma pessoa.

Uma pessoa, pode ter vários endereços.

E um endereço pode ser de uma pessoa fisica, ou juridica …

Nesse caso, justifica-se a herança de Pessoa -> Pessoa Fisica | Pessoa Juridica[/quote]

Se uma pessoa juridica pode ter varios enderecos e uma pessoa fisica soh pode ter um quantos enderecos tem a pessoa? Pessoa nao tem endereco?

Se voce fizer desta forma o codio que lida com enderecos nao eh polimorfico. Se este codio nao for polimorfico ele tem que tratar cada caso como m caso. Se ele nao eh polimorfico voce ja nao esta fazendo uso de heranca.

Ja que voce nao esta fazendo uso de heranca que tal assumir que uma pessoa tem 0 (ou 1, depende do dominio) ou mais enderecos? Vai atender os dois casos e voce nao ganhou nem perdeu nada alem de evitar uma hierarquia que conceitualmente nao existe e em termos de implementacao nao te da nada.

Note que eu nao estou dizendo que essa hierarquia nunca deva ser utilizada, ela pode fazer sentido em alguns casos mas eu nunca vi. E olha que ja trabalhei com billing de telefonia, previdencia privada e planos de saude, dominios que sao cheios de situacoes onde peoas fisicas e juridicas se confundem.

Tah, vamos la

Eu tenho uma entidade endereço, e uma entidade pessoa e outra pessoa jurídica.

Pessoa e Pessoa Jurídica são entidades diferentes (Não tem relação entre si).

Uma Pessoa tem um ou muitos endereços.

Uma Pessoa Jurídica tem apenas um endereço. (Não tem sentido uma Pessoa Jurídica tem vários endereços, uma Pessoa Jurídica tem filiais certo ?)

Como seria a representação em classes ?

Na boa, a cada dia que passa, percebo que OO ainda possui algumas limitações e paradigmas


[quote=tnaires]Olá
Só uma dúvida: há realmente a necessidade de usar composição na relação Cliente - Pessoa? Acho que só seria preciso fazer dessa forma se você fosse mudar a pessoa associada ao Cliente em tempo de execução… Seguindo a lógica, um cliente É - e não TEM - uma pessoa. Acho que você tá levando a regra da composição ao pé da letra demais.
Segue uma sugestão de implementação, que permite você determinar dinamicamente se uma pessoa será física ou jurídica:

[code]public interface CadastroNacional {
// Nas subclasses, você pode lançar um IllegalArgumentException se o cpf ou cnpj não for válido
public void validar();
}

public class CPF implements CadastroNacional {
private String cpf;

public CPF(String cpf) {
	this.cpf = cpf;

	validar();
}

public void validar() {
	// Código de validação de CPF
}

public String toString() {
	// Sobrescrevendo o método toString para formatar o cpf de forma adequada
}

}

public class CNPJ implements CadastroNacional {
private String cnpj;

public CNPJ(String cnpj) {
	this.cnpj = cnpj;

	validar();
}

public void validar() {
	// Código de validação de CNPJ
}

public String toString() {
	// Sobrescrevendo o método toString para formatar o cnpj de forma adequada
}

}

// Note que esta classe não é abstrata
public class Pessoa {
// Olha a composição aqui
private CadastroNacional cadastro;

public void setCadastroNacional(CadastroNacional cn) {
	// Aqui você pode passar um objeto do tipo CPF ou CNPJ
}

}

// Você ainda precisa da classe Cliente? Se sim, aqui vai:
public class Cliente extends Pessoa {

}
[/code]Se você preferir, pode fazer CadastroNacional uma classe abstrata em vez de uma interface.
Abraços[/quote]

Como seria a implementação disso no mapeamento com o hibernate ?

Como você quiser. Se elas não sao da mesma hierarquia não entendi o problema.

[quote=_filipe]
Na boa, a cada dia que passa, percebo que OO ainda possui algumas limitações e paradigmas[/quote]

Orientação a Objetos é um paradigma então não sei e entendi o que você quiz dizermas sim, como qualquer outro e limitado. Só não deixe que a linguagem te limite mais ainda, tente modelar isso em Ruby e algumas das limitações ipostas por tipagem estática em Java somem.

Ola

O grande problema é o seguinte, vou tentar ser mais prático.

A meses venho tentando descobrir uma solução para esse problema:

Duas entidades não relacionadas, distintas, possuem associação a uma entidade qualquer.

Exemplo:

Temos 3 classes:

Entidade Pessoa Física

  • id
  • nome
  • Collection de Telefones

Entidade Pessoa Jurídica

  • id
  • razão social
  • Collection de Telefones

Entidade Telefone

  • id
  • numero
  • A referencia para proprietário pode ser tanto para uma pessoa juridica, quanto fisica.

Entende mais ou menos aonde eu quero chegar ?

Pessoa Física, e Pessoa Juridica são entidades distintas, e ambas possuem uma lista de telefones, quando, eu vou modelar minha classe Telefone, preciso especificar quem é o proprietário da linha, porém o proprietário pode ser tanto uma pessoa física, quanto juridica !

O que você quer fazer é alo muito comum. Se você precisa modelar as ‘pessoas’ como classes separadas elas precisam ter um ancestral em comum (em Java) e você az com que o Proprietario do telefone seja deste tipo. É o que foi sugrido no início deste tópico:

class PessoaJuridica extends/implements Pessoa {}
class PessoaFisica extends/implements Pessoa {}
class Telefone{

 private Pessoa proprietario=null;
}

Isso é uso de polimorfismo.

O meu ponto é que esta modelagem de PesoaFisica e PessoaJuridica como duas classes diferentes não é mito eliz porque dificilmente você precisa deste nível de detalhe. Na maioria dos casos ser pf ou pj é um atributo da pessoa e não justifica a criação de ma classe própria.

Entao, mas tu não concorda comigo, que pessoa juridica tem atributos/caracteristicas diferentes de uma pessoa fisica … uma pessoa fisica possui rg, cpf, data de nascimento, uma pessoa juridica possui cnpj, funcionários e etc …

não é mais viável, tratar como coisas distintas ?

Depende do que você precisa, do que é o domínio do seu sstema. Talvez elas possam ser classes diferentes sm e talvez não precisem de um ancestral em comum. Ou talvez realmente um ancestral em comum eja necessário. Ou talvez apenas os dados devam ficar em uma clase isolada que varia de um para otro. Depende.

O que não dá é para assumir que a relação PF extends P, pj extends P seja uma regra como vemos na maioria das vezes. Tudo depende do que você está fazendo.

Saquei :wink:

ps: valeu pela ajuda meu querido !

Utilizando o mesmo exemplo que citei do telefone.

não é coerente criar uma interface pessoa, e sim uma classe pessoa.

é viável manter nessa classe pessoa (ancestral) uma collection de telefones ?

Ou a pessoa não deve possuir essa associação direta …

Outra dúvida:

Quais seriam os atributos da classe pessoa, apenas id, nome (olhe lá) e data de registro por exemplo ?

Os dados mais especificos estariam em suas classes filhas …

Abstraindo para o mundo real, acho que essa não seria a solução mais elegante para essa modelagem, mas nem pra tudo existem soluções elegantes !

Porque não seria coerente uma interface? Vai depender do que você espera de um Proprietario. Usar interfaces geralmente é melhor, tanto do ponto de vista técnico (proxies dinâmicos, hrança múltipla) quanto de modelagem (você especiica um comportamento e não uma implementação). Usar uma superclasse para esta relação geralmente só é vantagem quando ela não é abstrata e/ou já possui um bom candidato dentro suas classes, não precisa criar ma classe só para isso.

Mas tendo ou não uma interface a ergunta e: qual a vantagem em ter uma lista na superclasse? A uperclasse deve contêr coisas que são caracteristicas de todos os seus filhos, ter uma lista é uma delas? Voltando ao exemlo da interface, será que o que você precisa não é apenas que a classe tenha um método que retorna o(s) telefone(s)? Será que é tão importante como isso é implementado?

Os dados específicos ficam nas filhas, apesar que eu não conheço seu modelo o suficiente para achar que vcê deva ter essa herança de qualquer modo.

Legal cara, bacana

Entendi aonde quer chegar, ja imaginava que seria dificil ter uma resposta sem lhe enviar a modelagem do sistema e as especificações …

Mas me ajudou muito …

Agora, suponhamos que eu utilize interface para a pessoa, é possível mapear isso no hibernate ?

Quero dizer, eu precisarei criar uma tabela Pessoa !?

Você não persiste a interface, persiste a implementação. Pro ORM não importa.

uhnm cara,

então complicou, pq de acordo com a minha duvida no contexto Pessoa Juridica, Pessoa Fisica e Telefones, eu tinha pensado em um modelo fisico de banco de dados mais ou menos assim:

Pessoa

  • id (pk)
  • nome

PessoaFisica

  • Pessoaid (fk)
  • dataNascimento

PessoaJuridica

  • PessoaId (fk)
  • cnpj

Telefones

  • id
  • pessoaId (fk)
  • numero

vou ter que pensar em outra modelagem agora … algo mais proximo de:

PessoaFisicaTelefones

  • pessoaFisicaId
  • TelefoneID
  • Tipo

certo ?

Se fizer algo parecido com o citado acima, eu vou ter tantas tabelas no meu banco de dados … que vai ser complicadisso manter …