Ajuda com a classe Cliente usando herança

40 respostas
T

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

J

pessoa fisica e juridica ao mesmo tempo? oO

T

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

A

vc pode cria uma opção que e ambos

combo tipo Pessoa
1 Juridica
2 Fisica
3 Ambos

T

Disso eu sei, o problema

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

R

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.

T

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?

D

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

T

esse seu modelo é bem mais fácil mesmo

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

R

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 …

D

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.

T

você apagou o código?

D

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.

D

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

T

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

D

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
}
R

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(){
   }
}
T

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

D

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.

T

@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

D
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()));
	}
}
T
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

R

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<>();
T

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

S

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.

T

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

S

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 !

T

@saoj

Pensei a mesma coisa tratar cliente como Pessoa

mas nesse seu exemplo como trataria Cliente

S

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.

S

Please delete (post duplicado)

D

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.

T

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 !

S

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

T

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.

S

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.

T

Valeu pela ajuda…

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

Obrigado!!

T

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?

S

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:

S

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:

T

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

S

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