Ajuda com a classe Cliente usando herança

40 respostas
tmvolpato

Bom dia,

Eu sei que esse assunto já foi discutido em outros tópicos, mas não existe uma definição clara a ser tomada diante desse assunto
varia conforme a necessidade da aplicação

Preciso de um nível de abstração alto, para a classe Cliente

a aplicação está dessa maneira abaixo, estou usando Herança JOINED e separei PessoaFisica de PessoaJuridica
não vou usar essas 2 duas classes apenas para Cliente usarei em outras tbm por isso resolvi separar dessa maneira

mas o Cliente pode ser os 2 (ai que complica )como posso tratar isso, sem mexer na minha aplicação?

40 Respostas

JuniorMaia

pessoa fisica e juridica ao mesmo tempo? oO

tmvolpato

pode ser uma ou outra
isso vai ser definido na hora do cadastro

alcirBarros

vc pode cria uma opção que e ambos

combo tipo Pessoa
1 Juridica
2 Fisica
3 Ambos

tmvolpato

Disso eu sei, o problema

esta no diagrama da aplicação
para obter os atributos Pessoa Fisica e Juridica

rmendes08

Para mim o mais simples em termos de herança/composição é:

PessoaFisica É Pessoa
PessoaJuridica É Pessoa

Cliente TEM-UM Pessoa

daí você monta cadastros separados de Pessoa e Cliente. No cadastro do Cliente você simplesmente informa o código da pessoa.

tmvolpato

Mendes,

Pensei nisso ao optar por herança

mas o problema surgiu por que Cliente pode ser Fisica e Juridica

e meus atributos estão nessas classes que são (SuperClasses) e se eu estender Pessoa eu não tenho como obter esses atributos

tem como implementar a Classe Cliente nesse modelo que estou usando hoje?

drsmachado

Sinceramente, eu prefiro usar composição.
É mais simples e menos problemática

tmvolpato

esse seu modelo é bem mais fácil mesmo

mas no meu modelo você enxerga alguma solução?

rmendes08

tmvolpato:
Mendes,

Pensei nisso ao optar por herança

mas o problema surgiu por que Cliente pode ser Fisica e Juridica

e meus atributos estão nessas classes que são (SuperClasses) e se eu estender Pessoa eu não tenho como obter esses atributos

tem como implementar a Classe Cliente nesse modelo que estou usando hoje?

Cara, me dê um exemplo de um Cliente que pode ser Pessoa Física e Jurídica ao mesmo tempo, sério mesmo, gostaria de entender isso …

drsmachado

Camarada, não enxergo. Primeiro que esta regra de um cliente poder ser PJ e PF está, no MEU ponto de vista, errada.
Afinal, o cadastro será feito por CPF/CNPJ, não? Um PF associado a um CPF, um PJ a um CNPJ.
Além do mais, um Cliente podendo ser PJ e PF ao mesmo tempo, requeriria herança múltipla. Inexiste no java.
Há meios sim, de se obter um objeto filho a partir de uma instância da classe Pai, utilizando cast

Pessoa p = new PessoaFisica();
PessoaFisica pf = (PessoaFisica) p;

Plenamente possivel.

tmvolpato

você apagou o código?

drsmachado

rmendes08:
tmvolpato:
Mendes,

Pensei nisso ao optar por herança

mas o problema surgiu por que Cliente pode ser Fisica e Juridica

e meus atributos estão nessas classes que são (SuperClasses) e se eu estender Pessoa eu não tenho como obter esses atributos

tem como implementar a Classe Cliente nesse modelo que estou usando hoje?

Cara, me dê um exemplo de um Cliente que pode ser Pessoa Física e Jurídica ao mesmo tempo, sério mesmo, gostaria de entender isso …


++
Como eu disse, há um problema de lógica nesta afirmação. Até onde sei, um Cliente É PJ ou PF, onde o OU é exclusivo.

drsmachado

Perai, fui alterar e acabei apagando.
Já recoloco.

tmvolpato

Mendes como eu disse ali em cima

ele pode ser os dois mas não ao mesmo tempo
essa decisão seria tomada no cadastro do cliente

drsmachado

Segue.

//Pessoa
public class Pessoa{
	private Long codigo;
	private String nome;
	private Collection<Endereco> enderecos;
	private Collection<Telefone> telefones
	//getters e setters
}
//IPessoa -- não use I antes de uma interface, neste caso, é um exemplo apenas.
public interface IPessoa{
	public void setPessoa(Pessoa pessoa);
	public Pessoa getPessoa();
	public void setCadFederal(String cadFederal);
	public String getCadFederal();
	public void setCadEstadual(String cadEstadual);
	public String getCadEstadual();
	public void setRenda(Double renda);
	public Double getRenda();
}
//PessoaFisica
public class PessoaFisica implements IPessoa{
	private Pessoa pessoa;
	private String cpf;
	private String rg;
	private Double renda;
	
	//implementações
	public void setPessoa(Pessoa pessoa){
		this.pessoa = pessoa;
	}
	public Pessoa getPessoa(){
		return this.pessoa;
	}
	public void setCadFederal(String cadFederal){
		this.cpf = cadFederal;
	}
	public String getCadFederal(){
		return this.cpf;
	}
	public void setCadEstadual(String cadEstadual){
		this.rg = cadEstadual;
	}
	public String getCadEstadual(){
		return this.rg;
	}
	public void setRenda(Double renda){
		this.renda = renda;
	}
	public Double getRenda(){
		return this.renda;
	}
}
//PessoaFisica
public class PessoaJuridica implements IPessoa{
	private Pessoa pessoa;
	private String cnpj;
	private String inscEst;
	private Double renda;
	
	//implementações
	public void setPessoa(Pessoa pessoa){
		this.pessoa = pessoa;
	}
	public Pessoa getPessoa(){
		return this.pessoa;
	}
	public void setCadFederal(String cadFederal){
		this.cnpj = cadFederal;
	}
	public String getCadFederal(){
		return this.cnpj;
	}
	public void setCadEstadual(String cadEstadual){
		this.inscEst = cadEstadual;
	}
	public String getCadEstadual(){
		return this.inscEst;
	}
	public void setRenda(Double renda){
		this.renda = renda;
	}
	public Double getRenda(){
		return this.renda;
	}
}

Apenas uma idéia.
Ah, e o Cliente terá uma propriedade IPessoa

//Cliente
public class Cliente{
  private IPessoa iPessoa;//pode receber PessoaJuridica ou PessoaFisica
  //demais atributos
  //getters e setters
}
rmendes08

tmvolpato:
Mendes como eu disse ali em cima

ele pode ser os dois mas não ao mesmo tempo
essa decisão seria tomada no cadastro do cliente

Você pode usar Generics na sua classe Cliente, assim você parametriza o tipo do Cliente:

class Cliente<T extends Pessoa>{
   private T pessoa;

   public T getPessoa(){
   }
}
tmvolpato

rmendes08:
tmvolpato:
Mendes como eu disse ali em cima

ele pode ser os dois mas não ao mesmo tempo
essa decisão seria tomada no cadastro do cliente

Você pode usar Generics na sua classe Cliente, assim você parametriza o tipo do Cliente:

class Cliente<T extends Pessoa>{
   private T pessoa;

   public T getPessoa(){
   }
}

Dessa maneira

eu consigo indicar apenas uma classe Fisica ou Juridica dessa maneira certo?

Foi como ele disse la em cima eu precisaria de uma herança múltipla "Mas isso não existe em java"
para poder estender as duas classes.

é complicado esse assunto

drsmachado

Complicado por que você está vendo assim.
Como o rmendes indicou, a utilização de generics permitirá que apenas a instância da classe adequada, PF ou PJ seja utilizada.
Isso poderá ser definido no momento do cadastro e alterado psoteriormente, sem maiores problemas.

tmvolpato

@Mendes,
estou implementando essa sua ideia de generics

@Machado

machado nesse seu modelo você consegue dizer tranquilamente que tipo é o cliente
na classe produto por exemplo

drsmachado
tmvolpato:
@Mendes, estou implementando essa sua ideia de generics

@Machado

machado nesse seu modelo você consegue dizer tranquilamente que tipo é o cliente
na classe produto por exemplo

Tanto quanto o uso de generics, neste caso, eu posso verificar com instanceof...
public class Cliente {
	private IPessoa iPessoa;

	public void setiPessoa(IPessoa iPessoa) {
		this.iPessoa = iPessoa;
	}

	public IPessoa getiPessoa() {
		return iPessoa;
	}
	
	private String verificaPessoa(IPessoa ipes){
		if(ipes instanceof PessoaFisica){
			return "PF";
		}else {
			return "PJ";
		}
	}
	
	public static void main(String[] args) {
		Cliente c = new Cliente();
		c.setiPessoa(new PessoaFisica());
		System.out.println(c.verificaPessoa(c.getiPessoa()));
		c.setiPessoa(new PessoaJuridica());
		System.out.println(c.verificaPessoa(c.getiPessoa()));
	}
}
tmvolpato
drsmachado:
tmvolpato:
@Mendes, estou implementando essa sua ideia de generics

@Machado

machado nesse seu modelo você consegue dizer tranquilamente que tipo é o cliente
na classe produto por exemplo

Tanto quanto o uso de generics, neste caso, eu posso verificar com instanceof...
public class Cliente {
	private IPessoa iPessoa;

	public void setiPessoa(IPessoa iPessoa) {
		this.iPessoa = iPessoa;
	}

	public IPessoa getiPessoa() {
		return iPessoa;
	}
	
	private String verificaPessoa(IPessoa ipes){
		if(ipes instanceof PessoaFisica){
			return "PF";
		}else {
			return "PJ";
		}
	}
	
	public static void main(String[] args) {
		Cliente c = new Cliente();
		c.setiPessoa(new PessoaFisica());
		System.out.println(c.verificaPessoa(c.getiPessoa()));
		c.setiPessoa(new PessoaJuridica());
		System.out.println(c.verificaPessoa(c.getiPessoa()));
	}
}

estou testando aqui

valeu pela ajuda até o momento
@Machado
@Mendes

rmendes08

tmvolpato:
rmendes08:
tmvolpato:
Mendes como eu disse ali em cima

ele pode ser os dois mas não ao mesmo tempo
essa decisão seria tomada no cadastro do cliente

Você pode usar Generics na sua classe Cliente, assim você parametriza o tipo do Cliente:

class Cliente<T extends Pessoa>{
   private T pessoa;

   public T getPessoa(){
   }
}

Dessa maneira

eu consigo indicar apenas uma classe Fisica ou Juridica dessa maneira certo?

Foi como ele disse la em cima eu precisaria de uma herança múltipla "Mas isso não existe em java"
para poder estender as duas classes.

é complicado esse assunto

Nesse caso, você decide o tipo da pessoa no momento de declarar a variável:

Cliente<PessoaFisica> cpf = new Cliente<>();
   Cliente<PessoaJuridica> cpj = new Cliente<>();
tmvolpato

drsmachado:
Camarada, não enxergo. Primeiro que esta regra de um cliente poder ser PJ e PF está, no MEU ponto de vista, errada.
Afinal, o cadastro será feito por CPF/CNPJ, não? Um PF associado a um CPF, um PJ a um CNPJ.
Além do mais, um Cliente podendo ser PJ e PF ao mesmo tempo, requeriria herança múltipla. Inexiste no java.
Há meios sim, de se obter um objeto filho a partir de uma instância da classe Pai, utilizando cast

Pessoa p = new PessoaFisica();
PessoaFisica pf = (PessoaFisica) p;

Plenamente possivel.

Desse jeito eu enxergo os atributos, mas como vou salvar eles na minha classe Cliente

lembrando que individual so repassa os atributos pq ela é uma superclass

saoj

IPessoa é ruim demais! Eu não gosto… Nomenclatura ultrapassada. Quando eu vejo alguém usando essa nomenclatura desconfio na hora… Isso é pré-histórico e me lembra EJB1.

A questão principal é que não existe uma pessoa que não seja PessoaFísica ou PessoaJurídica, certo? Em outras palavras vc nunca vai instanciar Pessoa, mas apenas PessoaJuridica e PessoaFisica, certo? Pessoa então é apenas uma ESPECIFICACAO e não uma IMPLEMENTACAO.

Se esse for o caso então vc tem:

public interface Pessoa {

}
public abstract class AbstractPessoa implements Pessoa {

}
public class PessoaFisica extends AbstractPessoa {

}

public class PessoaJuridica extends AbstractPessoa {

}

Qualquer coisa diferente disso está errado. :slight_smile:

OBS: A class AbstractPessoa é opcional mais recomendável.

O código abaixo está errado:

private String verificaPessoa(IPessoa ipes){ if(ipes instanceof PessoaFisica){ return "PF"; }else { return "PJ"; } }

Tem que usar polimorfismo sempre. If para polimorfismo é um erro primário que todos nós já fizemos. O negócio é fazer uam vez depois nunca mais.

Polimorfismo correto não admite qualquer IF.

tmvolpato

saoj:
IPessoa é ruim demais! Eu não gosto…

A questão principal é que não existe uma pessoa que não seja PessoaFísica ou PessoaJurídica, certo? Em outras palavras vc nunca vai instanciar Pessoa, mas apenas PessoaJuridica e PessoaFisica, certo? Pessoa então é apenas uma ESPECIFICACAO e não uma IMPLEMENTACAO.

Se esse for o caso então vc tem:

public interface Pessoa {

}
public abstract class AbstractPessoa implements Pessoa {

}
public class PessoaFisica extends AbstractPessoa {

}

public class PessoaJuridica extends AbstractPessoa {

}

Qualquer coisa diferente disso está errado. :slight_smile:

OBS: A class AbstractPessoa é opcional mais recomendável.

O código abaixo está errado:

private String verificaPessoa(IPessoa ipes){ if(ipes instanceof PessoaFisica){ return "PF"; }else { return "PJ"; } }

Tem que usar polimorfismo sempre. If para polimorfismo é um erro primário que todos nós já fizemos. O negócio é fazer uam vez depois nunca mais.

Onde entraria Cliente ai ?

o problema esta ai, o cliente pode ser os 2 não ao mesmo tempo

saoj

O cliente vai CONTER (composicao) uma Pessoa.

E se vc quiser/precisar vc tb pode fazer o client SER uma pessoa, implementando Pessoa e delegando.

Qualquer coisa diferente disso está errado.

Assim:

public class Client implements Pessoa {

    private final Pessoa p;

    public Client(Pessoa p) {
       this.p = p;
   }

   // implementa os métodos de Pessoa e delega para p
}

Esse é o PATTERN decorator, o único que serve para alguma coisa. O resto é balela. Agora use esse pattern demais e vc fica com um sistema no estilo boneca-russa que ninguém entende. É para usar com muita parcimônia. Se vc está usando muito esse pattern significa que vc está complicando o simples. Por exemplo: Vc realmente precisa de dois objetos, Cliente e Pessoa !!!??? Não pode ser um só? Vc acabou de fazer o que 95% dos programadores fazem. Criou complexidade desnecessária para encher a boca e dizer: EU USEI O PATTERN DECORATOR !

tmvolpato

@saoj

Pensei a mesma coisa tratar cliente como Pessoa

mas nesse seu exemplo como trataria Cliente

saoj

tmvolpato:

@saoj

Pensei a mesma coisa tratar cliente como Pessoa

mas nesse seu exemplo como trataria Cliente

Leia isso que eu editei:

Não entendi a sua pergunta. Cliente é Cliente AND Cliente é Pessoa. Claro que Pessoa não é Cliente.

Conclusão: Vc introduziu complexidade no seu sistema. Para tudo e veja se não pode fazer um merge de Pessoa e Cliente numa classe só. Vai simplificar o seu sistema bastante.

saoj

Please delete (post duplicado)

drsmachado

saoj:
IPessoa é ruim demais! Eu não gosto… Nomenclatura ultrapassada. Quando eu vejo alguém usando essa nomenclatura desconfio na hora… Isso é pré-histórico e me lembra EJB1.

Por isso eu coloquei isto no código

//IPessoa -- não use I antes de uma interface, neste caso, é um exemplo apenas.  
public interface IPessoa{

saoj:

O código abaixo está errado:

private String verificaPessoa(IPessoa ipes){ if(ipes instanceof PessoaFisica){ return "PF"; }else { return "PJ"; } }

Tem que usar polimorfismo sempre. If para polimorfismo é um erro primário que todos nós já fizemos. O negócio é fazer uam vez depois nunca mais.

Polimorfismo correto não admite qualquer IF.


Concordo plenamente.

tmvolpato

Saoj,

Eu estou usando herança e tratando cliente como pessoa
so vou ter acesso aos atributos do pai
e não das filhas, se eu estende a classe Pessoa

como eu trataria isso

Você acha um erro trabalhar com herança nessa parte?

saoj:
O cliente vai CONTER (composicao) uma Pessoa.

E se vc quiser/precisar vc tb pode fazer o client SER uma pessoa, implementando Pessoa e delegando.

Qualquer coisa diferente disso está errado.

Assim:

public class Client implements Pessoa {

    private final Pessoa p;

    public Client(Pessoa p) {
       this.p = p;
   }

   // implementa os métodos de Pessoa e delega para p
}

Esse é o PATTERN decorator, o único que serve para alguma coisa. O resto é balela. Agora use esse pattern demais e vc fica com um sistema no estilo boneca-russa que ninguém entende. É para usar com muita parcimônia. Se vc está usando muito esse pattern significa que vc está complicando o simples. Por exemplo: Vc realmente precisa de dois objetos, Cliente e Pessoa !!!??? Não pode ser um só? Vc acabou de fazer o que 95% dos programadores fazem. Criou complexidade desnecessária para encher a boca e dizer: EU USEI O PATTERN DECORATOR !

saoj

Posta o código, por favor. Descrever código e arquitetura com palavras é conversa de maluco.

tmvolpato

Classe Pessoa

@Entity
@Table(name="PERSON")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="PERSON_TYPE" , discriminatorType=DiscriminatorType.STRING)
public abstract class Person implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Basic(optional=false)
	private Long id;
    
    @OneToOne(mappedBy="person",fetch=FetchType.EAGER, cascade=CascadeType.ALL)
    private Address address;
    
    @OneToOne(mappedBy="person",fetch=FetchType.EAGER, cascade=CascadeType.ALL)
    private Login login;
.
.
.

Classe Pessoa Fisica

@MappedSuperclass
public class Individual extends Person{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@NotNull
	@NotEmpty
	@Column(name="NAME", length=100, nullable=false)
	private String name;
	
	@NotNull
	@NotEmpty
	@Column(name="LAST_NAME", length=100, nullable=false)
	private String lastName;
	
	@NotNull
	@NotEmpty
	@Column(name="CPF")
	private String cpf;

Classe Pessoa Juridica

@MappedSuperclass
public class Company extends Person implements Serializable{

	private static final long serialVersionUID = 1L;
	
	
	@NotNull
	@NotEmpty
	@Column(name="FOUNDATION_OF_DATE",length=10,nullable=false)
	private Date foundationOfDate;
	
	@NotNull
	@NotEmpty
	@Column(name="CTR", unique=true,length=15,nullable=false)
	private String ctr;
	
	@NotNull
	@NotEmpty
	@Column(name="CNPJ", unique=true,length=15,nullable=false)
	private String cnpj;

A classe Cliente eu nao tenho nada pq estou procurando uma solução para implementar ela nesse modelo que estou passando

saoj:
tmvolpato:

Saoj,

Eu estou usando herança e implementando Pessoa
so vou ter acesso aos atributos do pai
e não das filhas

como eu trataria isso

Você acha um erro trabalhar com herança nesse modelo por exemplo?

Posta o código, por favor. Descrever código e arquitetura com palavras é conversa de maluco.

saoj

Dois problemas graves:

  1. Você está usando a porcaria do Hibernate. Evite a todo o custo. Veja como fica feio o seu beanzinho cheio daquelas anotacões absurdas. Leia esse thread inteiro e depois olha o MentaBean. Uma explicacao mais simplificada do MentaBean está aqui: http://www.mentaframework.org/mtw/Page/ORM/mentawai-orm-e-sql-builder

  2. Person tem que ser INTERFACE e nunca uma classe Abstrata. Espero que não seja o maravilhoso Hibernate que está te obrigando a fazer isso. Vc tem que usar aquele esquema de interface mais classes abstratas que eu postei. Vc já viu como as Collections do Java foram feitas?

A solucao do Cliente é aquela que eu postei.

Já no banco de dados tu vai ter duas tabelas. Uma para guardar os dados de PessoasJuridicas e outra para guardar os dados da pessoa física. E vc pode carregar todos os tipos de clientes ao mesmo tempo fazendo um JOIN em ambas as tabelas porque será garantido que um cliente não terá ambos.

AGORA TENTA ORGANIZAR ESSA ZONA COM AS ANOTACOES DO HIBERNATE ???

Hibernate cria um problema maior e não soluciona nada. Faca isso na mão com o bom e velho SQL. Banco-de-dados não dá para “abstrair” como o Hibernate tenta fazer. É uma insanidade e uma atente contra o principio KISS.

O único jeito correto de abstrair o banco-de-dados é usando DAOs e um query-builder com um mapeamento bem simples tipo o MentaBean faz. Inventar mágica e anotacoes malucas como o Hibernate faz é insanidade.

É aprender espanhol em cima de ingles para falar ingles melhor.

tmvolpato

Valeu pela ajuda…

vou fazer as mudanças aqui
Deu pra ter uma outra visão agora…

Obrigado!!

tmvolpato

duvida aqui

ao implementar a interface Pessoa em Cliente
vou obter todos os atributos da classe Fisica e juridica
seria isso o correto? ou teria outra maneira?

saoj

tmvolpato:
duvida aqui
ao implementar a interface Pessoa em Cliente
vou obter todos os atributos da classe Fisica e juridica
seria isso o correto? ou teria outra maneira?

Não entendi. O que vc falou não faz sentido.

Quando o Cliente implementa Pessoa ele vai ter que RECEBER uma Pessoa no construtor, que pode ser qualquer uma.

Daí ele vai DELEGAR todos os métodos de pessoa para esse objeto que ele recebe no construtor. O famoso e infame DECORATOR pattern.

Vc diz que PessoaJuridica e PessoaFisica não possuem uma interface comum ??? Aí ferrou !!! Esquece tudo que eu falei então. :frowning: :slight_smile:

saoj

Agora fiquei vendido no lance. Eventualmente vc vai ter que fazer um casting da Pessoa para PessoaJuridica ou PessoaFisica.

Acho que o melhor é ter interface Cliente e ClienteFisico e ClienteJuridico. Não dá para ter só um Cliente assim como não dá para ter só uma Pessoa.

O ideal é não complicar e fazer um merge do Cliente e da Pessoa num objeto só !!!

Peco ajuda para os estudantes,. Agora não sei o que é melhor. :slight_smile:

tmvolpato

complicado msm
eu comecei a seguir suas dicas e cai nesse problema

da interface pessoa ter todos os atributos de Física e Jurídica
e cliente implementando ela seria obrigatório implementar todos

esse tbm não seria um cenário ideal concorda @SaoJ

tbm peço ajuda

saoj

Joguei essa discussão pra cá => http://www.guj.com.br/java/273262-complexidade-x-simplicidade--teoricos-x-praticos

Criado 17 de maio de 2012
Ultima resposta 17 de mai. de 2012
Respostas 40
Participantes 6