Pessoa Física e Jurídica

Olá pessoal,

estou com um problema e gostaria que me ajuda-sem da melhor maneira possível. Li vários tópicos em diversos fóruns e ainda algumas dúvidas prevalecem. Desses diversos materiais que encontrei, tentei implementar e não consegui. Espero que esse tópico seja útil e possa trazer uma resposta, à qual não encontrei em diversos outros.

Quero fazer melhor proveito possível, respeitando a orientação a objetos.

Bom, vamos ao que interessa!

Caso do sistema:

Cliente e fornecedor será cadastrado no sistema conforme sua natureza (Pessoa Física, Pessoa Jurídica).

Visão:

  • Cliente é uma pessoa;
  • Fornecedor é uma pessoa;
  • Pessoa possui apenas um tipo de natureza;
  • Tipo física possui tais atributos: Nome, CPF, RG;
  • Tipo jurídica possui tais atributos: Nome Fantasia, Razão Social, CNPJ, Inscrição Estadual

Resumindo:

Cliente e fornecedor podem ser pessoas do tipo física ou jurídica.

Problema:

Como implementaria esse caso? (interface, abstract, herança)

Cria as super classes como abstratas.

public abstract class Pessoa {

}
public abstract class PessoaFisica extends Pessoa{

}
public abstract class PessoaJuridica extends Pessoa{

}

E suas classes concretas.

public class Cliente extends PessoaFisica{

}
public class Fornecedor extends PessoaJuridica{

}

[quote=jweibe]Cria as super classes como abstratas.

[code]
public abstract class Pessoa {

}
public abstract class PessoaFisica extends Pessoa{

}
public abstract class PessoaJuridica extends Pessoa{

}
[/code][/quote]

Acho que isso não seria correto, pois se utiliza herança quando existe uma relação “É UM”.

[quote=jweibe]E suas classes concretas.

[code]
public class Cliente extends PessoaFisica{

}
public class Fornecedor extends PessoaJuridica{

}
[/code][/quote]

Cliente pode ser também pessoa jurídica e fornecedor pode ser pessoa física.

[code]
public abstract class Pessoa {
enum TipoPessoa {
PESSOA_FISICA, PESSOA_JURIDICA;
}
}

public class Cliente extends Pessoa{

}
public class Fornecedor extends Pessoa{

}[/code]

Ogora o tipo de pessoa você define na criação do objeto.

Alguém possui mais exemplos?

Baseando-se nessas frases do livro Design Patterns:

Evite herança, prefira composição” e “Programe voltado às interfaces e não à implementação”.

[quote=polianomartini]Alguém possui mais exemplos?

Baseando-se nessas frases do livro Design Patterns:

Evite herança, prefira composição” e “Programe voltado às interfaces e não à implementação”.[/quote]

Com composição:

public class Cliente {

private Pessoa pessoaRepresentada;

public Cliente(Pessoa pessoa) {
this.pessoaRepresentada = pessoa;
}

}

//Mesma coisa para fornecedor

public abstract class Pessoa {

}

public class PessoaFisica extends Pessoa {

}

public class PessoaJuridica extends Pessoa {

}

Note que somente o cliente e o fornecedor têm necessidade de usar composição, não pessoa física/jurídica.

[]'s

Pessoal, fiz da seguinte maneira:

[code]public abstract class Documento {

public abstract String getTipoPessoa();

public abstract String getValidar();

}[/code]

[code]public class DocumentoFisica extends Documento {

private String cpf;

public String getCpf() {
	return cpf;
}

public void setCpf(String cpf) {
	this.cpf = cpf;
}

@Override
public String getTipoPessoa() {
	return "Pessoa Física";
}

@Override
public String getValidar() {
	// Algoritmo para validar
	return "Validado!";
}

}[/code]

[code]public class DocumentoJuridica extends Documento {

private String cnpj;

public String getCnpj() {
	return cnpj;
}

public void setCnpj(String cnpj) {
	this.cnpj = cnpj;
}

@Override
public String getTipoPessoa() {
	return "Pessoa Jurídica";
}

@Override
public String getValidar() {
	// Algoritmo para validar
	return "Validado!";
}

}[/code]

[code]public abstract class Contato {

public Documento documento;

public Documento getDocumento() {
	return documento;
}

public void setDocumento(Documento documento) {
	this.documento = documento;
}

}[/code]

[code]public class Cliente extends Contato {

private Integer codigo;

public Integer getCodigo() {
	return codigo;
}

public void setCodigo(Integer codigo) {
	this.codigo = codigo;
}

}[/code]

Observando alguns exemplos fiz dessa maneira, depois criei a classe principal para fazer um teste:

[code]public class Principal {

public static void main(String[] args) {
	
	DocumentoFisica df = new DocumentoFisica();
	df.setCpf("123.456.789-10");
	
	Cliente c = new Cliente();
	c.setCodigo(1);
	c.setDocumento(df);

}

}[/code]

Amarrei o documento para o cliente, porém como faria pra capturar o cpf do cliente? Quando tento “c.getDocumento().”, me vem apenas os métodos que criei na classe Documento.

O que fiz de errado? Implementei da maneira correta?

Herere, poliano o que fazemos eh do tempo em que computador era a valvula, mas imagine um banco grande, grande mesmo, ai voce mistura cliente e fornecedores, onde os seus fornecedores sao clientes e vice-versa, entao pra evitar o que nos chamamos de “consolencias” separamos clientes e fornecedores em tabelas diferentes, imagine entao um banco legado, que cecero que vira.

Mas claro que são tabelas diferentes do banco. Não intendi bem seu comentário.

Alguém pode me ajudar?

Acho que uma maneira de fazer o que você quer é utilizar instanceof para identificar e cast para ter acesso aos métodos:

if(c.getDocumento() instanceof DocumentoFisica) { System.out.print("CPF:"+((DocumentoFisica) c.getDocumento()).getCpf()); } if(c.getDocumento() instanceof DocumentoJuridica) { System.out.print("CNPJ:"+((DocumentoJuridica) c.getDocumento()).getCnpj()); }

[quote=jamirdeajr]Acho que uma maneira de fazer o que você quer é utilizar instanceof para identificar e cast para ter acesso aos métodos:

if(c.getDocumento() instanceof DocumentoFisica) { System.out.print("CPF:"+((DocumentoFisica) c.getDocumento()).getCpf()); } if(c.getDocumento() instanceof DocumentoJuridica) { System.out.print("CNPJ:"+((DocumentoJuridica) c.getDocumento()).getCnpj()); }[/quote]

Nooooooosssa… totalmente procedural, não flexível… que “beleza” de dica!

Eu tenho algo assim:

[code]public abstract class Pessoa

{

/**

 * 

 * Razão Social para Pessoa Juridica

 * Nome para Pessoa Fisica

 * 

 */

public abstract String getNomeExibicao();



/**

 * CPF para Pessoa Fisica

 * CNPJ para Pessoa Juridica

 * 

 */

public abstract String getRegistroNacional();

}[/code]

E a implementação de PessoaFisica e PessoaJuridica estendem de Pessoa e implementam o retorno da informação correta.

O que acontece é o seguinte: você precisa modelar seus objetos da maneira como eles acontecem no mundo real. Como acontece no mundo real? Cada tipo de documento (RG, CPF, etc.) é um documento. Óbvio, você tem documentos que são usados por pessoas físicas e por pessoas jurídicas, mas é certo modelá-los assim? Sim e não, depende… cada documento específico deveria ter sua própria classe, já que eles podem ter sua própria lógica de validação. Assim, seria interessante você fazer mais ou menos assim:


public abstract class Pessoa {

public abstract Collection<Documento> getDocumentos();

}

public class PessoaFisica {

private Documento documento;

public Collection<Documento> getDocumentos() {
return Collections.singletonList(documento);
}
}

public abstract class Documento {

public abstract void validar() throws ValidationException;

}

public class RG extends Documento {

private String numero;

private Date dataEmissao;

public void validar() throws ValidationException {
//Ponha aqui lógica de validação para RG
}

}

E assim por diante. Note que eu não coloquei todas as classes porque queria somente demonstrar o conceito. Dessa maneira, seu sistema fica muito mais flexível (porque, por exemplo, se o documento principal de pessoa física deixar de ser o RG, por exemplo, você só precisa trocar a instância do atributo rg. Se o seu fornecedor for pessoa física ou pessoa jurídica, não importa, porque você só vai precisar referenciar a superclasse Pessoa no seu código. E assim por diante.

[]'s

[quote=asaudate][quote=jamirdeajr]Acho que uma maneira de fazer o que você quer é utilizar instanceof para identificar e cast para ter acesso aos métodos:

if(c.getDocumento() instanceof DocumentoFisica) { System.out.print("CPF:"+((DocumentoFisica) c.getDocumento()).getCpf()); } if(c.getDocumento() instanceof DocumentoJuridica) { System.out.print("CNPJ:"+((DocumentoJuridica) c.getDocumento()).getCnpj()); }[/quote]

Nooooooosssa… totalmente procedural, não flexível… que “beleza” de dica![/quote]

Alexandre Saudate, você tem toda razão. Desculpe se ofendi seu intelecto OO.
Realmente é mais um jeitinho de contornar, apenas comecei a achar que não seria algo tão sério a ponto de se perder tanto tempo pra encontrar uma solução “perfeita”.
Então, por favor esqueçam o que eu falei e sigam em frente.

[quote=asaudate]O que acontece é o seguinte: você precisa modelar seus objetos da maneira como eles acontecem no mundo real. Como acontece no mundo real? Cada tipo de documento (RG, CPF, etc.) é um documento. Óbvio, você tem documentos que são usados por pessoas físicas e por pessoas jurídicas, mas é certo modelá-los assim? Sim e não, depende… cada documento específico deveria ter sua própria classe, já que eles podem ter sua própria lógica de validação. Assim, seria interessante você fazer mais ou menos assim:


public abstract class Pessoa {

public abstract Collection<Documento> getDocumentos();

}

public class PessoaFisica {

private Documento documento;

public Collection<Documento> getDocumentos() {
return Collections.singletonList(documento);
}
}

public abstract class Documento {

public abstract void validar() throws ValidationException;

}

public class RG extends Documento {

private String numero;

private Date dataEmissao;

public void validar() throws ValidationException {
//Ponha aqui lógica de validação para RG
}

}

E assim por diante. Note que eu não coloquei todas as classes porque queria somente demonstrar o conceito. Dessa maneira, seu sistema fica muito mais flexível (porque, por exemplo, se o documento principal de pessoa física deixar de ser o RG, por exemplo, você só precisa trocar a instância do atributo rg. Se o seu fornecedor for pessoa física ou pessoa jurídica, não importa, porque você só vai precisar referenciar a superclasse Pessoa no seu código. E assim por diante.

[]'s[/quote]

Legal essa modelagem.
Pegando o seguinte cenário:

Pessoa pessoa = new PessoaFisica(); pessoa.addDocumento( new RG("1111", 21/04/2011) );

Agora e se eu quero pegar o numero de RG dessa PessoaFisica? No seu ponto de vista, qual seria a maneira mais adequada?

Collection documentos = pessoa.getDocumentos(); //.... e para pegar o RG? só iterando e comparando o tipo de objeto ou tem alguma maneira mais elegante?

Viajando um pouco…
o ideal seria ter um método que fizesse esse filtro (mas mesmo assim não tem como escapar da verificação instanceof, que teria que ser feita no método ofType):

RG documento = pessoa.getDocumentos().ofType(RG.class);

[quote=RafaelViana][quote=asaudate]O que acontece é o seguinte: você precisa modelar seus objetos da maneira como eles acontecem no mundo real. Como acontece no mundo real? Cada tipo de documento (RG, CPF, etc.) é um documento. Óbvio, você tem documentos que são usados por pessoas físicas e por pessoas jurídicas, mas é certo modelá-los assim? Sim e não, depende… cada documento específico deveria ter sua própria classe, já que eles podem ter sua própria lógica de validação. Assim, seria interessante você fazer mais ou menos assim:


public abstract class Pessoa {

public abstract Collection<Documento> getDocumentos();

}

public class PessoaFisica {

private Documento documento;

public Collection<Documento> getDocumentos() {
return Collections.singletonList(documento);
}
}

public abstract class Documento {

public abstract void validar() throws ValidationException;

}

public class RG extends Documento {

private String numero;

private Date dataEmissao;

public void validar() throws ValidationException {
//Ponha aqui lógica de validação para RG
}

}

E assim por diante. Note que eu não coloquei todas as classes porque queria somente demonstrar o conceito. Dessa maneira, seu sistema fica muito mais flexível (porque, por exemplo, se o documento principal de pessoa física deixar de ser o RG, por exemplo, você só precisa trocar a instância do atributo rg. Se o seu fornecedor for pessoa física ou pessoa jurídica, não importa, porque você só vai precisar referenciar a superclasse Pessoa no seu código. E assim por diante.

[]'s[/quote]

Legal essa modelagem.
Pegando o seguinte cenário:

Pessoa pessoa = new PessoaFisica(); pessoa.addDocumento( new RG("1111", 21/04/2011) );

Agora e se eu quero pegar o numero de RG dessa PessoaFisica? No seu ponto de vista, qual seria a maneira mais adequada?

Collection documentos = pessoa.getDocumentos(); //.... e para pegar o RG? só iterando e comparando o tipo de objeto ou tem alguma maneira mais elegante?

Viajando um pouco…
o ideal seria ter um método que fizesse esse filtro (mas mesmo assim não tem como escapar da verificação instanceof, que teria que ser feita no método ofType):

RG documento = pessoa.getDocumentos().ofType(RG.class);

Das duas uma: ou você coloca um método getNumero() na própria classe Documento (afinal, todo documento tem um número) ou, caso o documento necessário seja sempre um RG, você troca o tipo do atributo. Varia de acordo com a necessidade.

EDIT: Só não faça testes de acordo com o tipo, pelo amor de James Gosling!

[]'s

Poderia me explicar ou indicar algum link por que devo evitar fazer o teste pelo tipo?