Não sei que problemas tera, mas achei extremamente confuso.
Uma coisa q eu não faço é herdar da da pessoa_juridica para mim pessoa_fisica e pessoa_juridica herdam de uma classe pessoa. Um cliente, uma empressa ou prefeitura seria composto por um cadastro pessoa_fisica ou pessoa_juridica! Isso faz sentido quando um cliente ou um forncedor pode ser tanto uma pessoa juridica quando física.
Claro que isso que eu disse faz sentido nos dominios nos quais trabalhei. No seu pode ser totalmente válido.
thiagodelgado
Concordo com o amigo acima, vou deixar um exemplo que costumo usar,
não sei se é o mais correto, mas acho que dá pra dar uma clareada pra ti!
Segue em anexo, qualquer dúvida, só perguntar!
Abraço!
B
Bruno_Reis
Obrigado!
Então
os métodos de acesso coloco nas classes dependentes, certo?
e os outros objetos comuns relacionados? generalizo? ex. imóvel, endereco, telefone,
coloco na superclasse?
public class Pessoa {
private long id;
private Imovel imovel;
private Telefone telefone;
}
e se eu criar uma classe Cliente e outra Fornecedor?
public class Cliente {
private long id;
private Pessoa pessoa;
}
public class Fornecedor {
private long id;
private Pessoa pessoa;
}
devo criar métodos de acesso para ela com delegação?
ou devo utilizar os métodos existentes em PessoaFisica e PessoaJuridica?
F
Fabricio_Langer
E quando o cara Cliente/Fornecedor for produtor rural? ele tem CPF e IE, nao tem CNPJ?
eu tive esse problema com meu cadastro de fornecedor
tem coisas que nao compensa abstrair,
nao costumo usar muita abstração em entidades de dominio
eu costumo usar mta abstração em componentes do projeto, como BCs, DAOs, Formularios Swing, Controllers
B
Bruno_Reis
realmente, produtor rural não tem cnpj (parece que agora está tendo)
candidatos políticos são pessoas que tem cnpj
o que é abstração? não é identificar objetos da realidade?
há como não abstrair em OO?
F
Fabricio_Langer
talvez tenha usado a expressão errada, quando digo que nao compensa abstrair, quero dizer que, em muitos casos
procuram enxugar ao maximo uma classe, criando classes pais, com propriedades similares, quando na verdade, poderiam fazer algo mais simples
thiagodelgado
Ai entra o conceito do polimorfismo, você pode criar os métodos que são comuns à todas as Classes que extenderem a super classe, dentro da própria super classe, criando uma interface, por ex,
Digamos que a classe Pessoa tem o método cadastraPessoa, ok, você cria uma interface, declara esse método e implementa a interface nas classes, criando assim
uma “regra” de que todas essas classes irão executar esse método, porém cada uma de uma maneira diferente
public interface ConfiraEssaSintaxePoisEstouSemCafe{
public void fazerCafe();
}
Caso seu problema seja como o do amigo do produtor rural, vale a pena pensar em dar uma estudada em Annotation e Reflection,
é um mundinho interessante, conheço muito pouco, mas gostei do pouco que conheci!
Desculpa mesmo amigo, mas é sério, estou sem café rs
B
Bruno_Reis
valeu Thiago, valeu Fabrício
entretanto
implementando a Superclasse de uma interface, as classes descendentes já serão, por herança, implementadas da interface também?
peço que veja acima, meus papéis
Fornecedor que possui um tipo de pessoa
Cliente que possui tipo de pessoa
Transportador que possui tipo de pessoa
pode ser assim?
B
Bruno_Reis
e os outros objetos
poderei fazer assim?
public class Pessoa {
private Imovel imovel;
private ContratoAluguel contratoAluguel;
private Veiculo veiculo;
}
x111
Bom pessoal, desculpe pela demora em responder, mas o tempo estava corrido.
Para o caso do de Pessoa, Pessoa Fisica, Pessoa Juridica, Produtor Rural acima mencionados eu adotaria o padrão Template Metod.
Na classe Pessoa colocaria as informações que qualquer pessoa realmente tem, como endereço e telefone. Nessa classe implementaria um metodo abstrato chamado tipoPessoa, que retornaria o valor de uma Enumeração que listaria os tipos de Pessoas. (PF, PJ, Produtor Rural, etc.). Esse metodo seria implmentado nas classes que herdam de Pessoa de modo que as classes que utilizam a classe Pessoa não teriam que fazer um instanceof para saber com qual classe estão lidando.
Nesse caso não vejo a necessidade de polimorfismo, pois cada classe que tem suas próprias caracteristicas. Uma PF tem CPF, uma pessoa juridica tem CNPJ e Insc. Municipal e Insc. Estadual. Produtor Rural tem IE e CPF, mas todas tem em comum o endereço e Telefone isso é comum a todas as classes então faz sentido elas herdarem esse comportamento. O unico comportamento que utiliza polimorfismo seria realmente o metodo de retorno tipoPessoa.
Dependendo de como seja o dominio da aplicação um cliente pode ser uma PF, uma PJ ou PR. Então a Classe cliente teria o formato descrito pelo bruno
public class Pessoa {
private Imovel imovel;
private ContratoAluguel contratoAluguel;
private Veiculo veiculo;
}
.......
public class Cliente {
private long id;
private Pessoa pessoa;
}
Na hora do cadastro seria definido o tipo de pessoa ou seja
Cliente = new Cliente(new PessoaJuridica());
ou
Cliente = new Cliente(new PessoaFisica())
......
//Para saber o tipo de cliente
if (Cliente.getPessoa().tipoDePessoa() == TipoDePessoa.PJ)
Cliente.getPessoa().getCNPJ();
Esse é um exemplo de arquitetura e não é valido para tudo. Se uma empresa só vende para Pessoa Juridica, então não faz sentido ter todo esse trabalho por exemplo.
Uma regra que deve ser sequida para todo o projeto é priorizar a composição a herança. Isso permite que o projeto seja facilmente expandido. Vejamos o caso acima.
Ao compormos objeto cliente de um cadastro de Pessoa ao invés de usar herança (cliente herdar de pessoa física por exemplo) facilita a expanção do sistema, pois podemos acresentar quaisquer outros cadastros, como PessoaJuridica e ProdutorRural. O Cliente continua o mesmo só muda o cadastro em runtime.
No mesmo exemplo podemos todar as classes cadastros de Objetos CNPJ, CPF, IE. Essas classes podem ser compartilhadas, um exemplo é o produtor rural que possui CPF e IE. Assim se o CPF possui um método de validação ele será compartilhado e não duplicado.
Agora um cuidado que temos que ter nesse momento é não confurdirmos atividade com o cadastro. Utilizemoscaso do produtor rural, nessa situação o cadastro é realmente diferente e possui particularidades. Agora no caso de uma igreja ou uma ong? Ambas tem CNPJ, mas devemos criar um cadastro individual para cada?
Não, pois ambas são PJ, porém em atividades distintas.
B
Bruno_Reis
Xandy, bom dia
Muito bom o que você disse. Entretanto.
Com essa abstração, eu não teria + flexibilidade?
Empresa, Pessoa, como uma coisa concreta, existente na realidade
Possuindo um conceito jurídico denominado “TipoJurídico” ou “Pessoa” possuindo 2 tipos: PessoaFísica, PessoaJurídica
Possuindo também um papel representado na sociedade, Vendedor, Cliente, Fornecedor,
Não seria aceitável também, ficaria mais complexo, mas mais flexível.
Pois poderia criar vários objetos do mundo real, possuindo conceitos.
Poderia criar, igreja, ong, empresa, prefeitura, todos possuindo conceitos jurídicos e papéis.
Empresa possui um conceito Pessoa Jurídica e vários papéis, Cliente, Fornecedor, Transportador.
Pessoa possui um conceito Pessoa Física e vários papéis, Cliente, Fornecedor, Prestador, Transportador, etc.
Não seria interessante separar, coisas existentes, concretas, de conceitos?
O que você acha?
x111
Bruno Reis:
Xandy, bom dia
Muito bom o que você disse. Entretanto.
Com essa abstração, eu não teria + flexibilidade?
Empresa, Pessoa, como uma coisa concreta, existente na realidade
Possuindo um conceito jurídico denominado “TipoJurídico” ou “Pessoa” possuindo 2 tipos: PessoaFísica, PessoaJurídica
Possuindo também um papel representado na sociedade, Vendedor, Cliente, Fornecedor,
Não seria aceitável também, ficaria mais complexo, mas mais flexível.
Pois poderia criar vários objetos do mundo real, possuindo conceitos.
Poderia criar, igreja, ong, empresa, prefeitura, todos possuindo conceitos jurídicos e papéis.
Empresa possui um conceito Pessoa Jurídica e vários papéis, Cliente, Fornecedor, Transportador.
Pessoa possui um conceito Pessoa Física e vários papéis, Cliente, Fornecedor, Prestador, Transportador, etc.
Não seria interessante separar, coisas existentes, concretas, de conceitos?
O que você acha?
Pera ai que esta havendo uma confusão, estou falando de coisas concretas! Eu penso em pessoas físicas e juridicas como um cadastro e não como pessoa. Esse cadastro é algo concreto. Um cliente, por exemplo, ele pode “ter” um cadastro de pessoa física ou um cadastro de pessoa juridica, pois digamos que o sistema seja feito para uma loja que venda para ambos. A única coisa abstrata no caso seria a classe Pessoa. Eu “abstraio” a classe pessoa, por que ela tem um comportamento em comum com várias classes. É esse comportamento que forma a super classe. Uma PJ e uma PF tem em comum Endereço e Telefone, por exemplo, e esse comportamento em comum vai formar a super classe Pessoa. Agora, dependendo do caso, um Fornecedor pode ser obrigadoriamente composto por pessoas jurídicas. Muitas empresas, por exemplo, só compram de pessoas juridicas. Nesse dominio, eu teria uma classe Cliente que faria referencia para uma classe PessoaJuridica ou PessoaFisica, essa referencia seria definida em runtime. O fornecedor, nesse caso, faria referencia apenas a classe PessoaJuridica. O meu cadastro é coisa concreta, tanto é que nesse exemplo que dei um cliente PJ também pode ser um forncedor! Se alterarmos o cadastro desse cliente, ele seria atualizado no cadastro de fornecedor!
Em relação ao sua arquitetura, eu vejo alguns problemas. Pois uma Pessoa Fisica herda de TipoJuridico. Até ai tudo bem, mas o TipoJuridico é composto de Pessoa e Empresa. Ai, a meu ver, deixa de fazer sentido, pois como uma pessoa Física conteria em seus atributos uma empresa e uma pessoa? A mesma coisa se aplica a PJ, ela “É” uma empresa, fica estranho ela conter uma empressa na verdade uma “Empresa” possui um “Cadastro de Pessoa Juridica” no mundo real.
Sua abstração do TipoJuridico, do qual você herda Pessoa Fisica e Pessoa Juridica esta sobrecarregado. A propósito, uma abstração, não necessariamente é uma classe abstrata, pode ser uma classe concreta.
Com relação aos papeis, fico em duvida se eles fazem ou não sentido, isso só analisando o dominio. Mas no caso do papel não faz sentido ele ser composto por um tipo juridico! A meu ver o cliente e fornecedor é que conteriam cada um uma refencia a um tipo juridico!
A meu ver o que faria mais sentido e com uma flexibidade muito maior
B
Bruno_Reis
Até ai tudo bem, mas o TipoJuridico é composto de Pessoa e Empresa.
olhe direitinho o desenho, por favor
o TipoJurídico não possui uma empresa ou pessoa
o TipoJurídico é parte de uma pessoa ou empresa
outro detalhe, PessoaFisica e PessoaJuridica, é um tipo jurídico, conceito
uma pergunta, há como uma coisa concreta herdar de uma coisa abstrata? conceito?
no seu desenho Pessoa, na verdade é um TipoJuridico. Uma empresa não pode herdar de uma pessoa.
o seu desenho é o mesmo que o meu, entretanto no meu, o nome da superclasse é TipoJurídico, no seu, é Pessoa(conceito)
quando eu vou comprar alguma coisa, eu vou numa empresa, e não numa pessoa jurídica
um médico cuida de uma pessoa, e não de uma pessoa física, então teríamos também a classe EmpresaFísica
sei que a maioria do pessoal faz assim, PF extends Pessoa, PJ extends Pessoa
todo mundo bebe coca-cola, mas, faz bem para saúde beber coca-cola?
B
Bruno_Reis
acho que deve existir
uma separação da realidade e dos conceitos
se quisermos criar
BarracaFeira
teremos facilidade
ela terá um TipoJurídico ou Pessoa(conceito)
há alguma outra abstração aqui no GUJ sem ser PJ extends Pessoa, PF extends Pessoa?
x111
Bruno Reis:
Até ai tudo bem, mas o TipoJuridico é composto de Pessoa e Empresa.
olhe direitinho o desenho, por favor
o TipoJurídico não possui uma empresa ou pessoa
o TipoJurídico é parte de uma pessoa ou empresa
outro detalhe, PessoaFisica e PessoaJuridica, é um tipo jurídico, conceito
uma pergunta, há como uma coisa concreta herdar de uma coisa abstrata? conceito?
no seu desenho Pessoa, na verdade é um TipoJuridico. Uma empresa não pode herdar de uma pessoa.
o seu desenho é o mesmo que o meu, entretanto no meu, o nome da superclasse é TipoJurídico, no seu, é Pessoa(conceito)
quando eu vou comprar alguma coisa, eu vou numa empresa, e não numa pessoa jurídica
um médico cuida de uma pessoa, e não de uma pessoa física, então teríamos também a classe EmpresaFísica
sei que a maioria do pessoal faz assim, PF extends Pessoa, PJ extends Pessoa
todo mundo bebe coca-cola, mas, faz bem para saúde beber coca-cola?
Desculpe é a presa, realmente desconsidere meu comentário anterior. na presa, inverti o sentido da composição (Faz séculos que não mexo com UML)
Realmente ai faz sentido com exceção do Papel. A classe juridica não deve conter o papel, pois isso não faz parte dela, você esta sobrecarregando-a.
As classes Empressa e Pessoa devem conter o Papel.
A propósito, para que se destinha essa arquitetura? Estou estranhando os nomes das classes e suas relações
B
Bruno_Reis
Xandy
obrigado por responder
o que eu preciso na verdade é criar uma empresa possuindo vários papéis
e uma pessoa possuindo vários papéis
porém na tabela papel do banco eu teria que ter duas FK, pessoa_id, e empresa_id
aí não dá, porque uma ou outra FK vai ficar null
como proceder neste caso?
B
Bruno_Reis
é para um sistema de vendas comum
ta parecendo que é mais simples mesmo
Pessoa Jurídica extender de Pessoa
e “mandar brasa” com outro detalhe do sistema
estou parado nisso
rsrsr
é que pensei que tendo uma classe concreta Pessoa, Empresa, BarracaNaFeira, Igreja, Ong
ficaria mais fácil de migrar a classe em outra regra de negócio, pois esses objetos Pessoa, Empresa, Barraca, vão existir no mundo
independente de conceitos
x111
Bruno Reis:
Xandy
obrigado por responder
o que eu preciso na verdade é criar uma empresa possuindo vários papéis
e uma pessoa possuindo vários papéis
porém na tabela papel do banco eu teria que ter duas FK, pessoa_id, e empresa_id
aí não dá, porque uma ou outra FK vai ficar null
como proceder neste caso?
Ai você tem um problema! Da forma que tu colocou no diagrama de classes e me disse anteriormente. Papel é um objeto valor de Empresa e pessoa, ou seja você carrega o Papel a partir da Pessoa ou da Empresa. Desse modo a referencia para o papel deve estar em pessoa e não contrario.
Outra coisa qual o comportamento da super classe papel, ela faz o que afinal?
O que você quer dizer com uma “Empresa ou Pessoa possuindo vários Papeis”?
Qual a finalidade do papel afinal, qual o comportamento dessa classe?
x111
Bruno Reis:
é para um sistema de vendas comum
ta parecendo que é mais simples mesmo
Pessoa Jurídica extender de Pessoa
e “mandar brasa” com outro detalhe do sistema
estou parado nisso
rsrsr
é que pensei que tendo uma classe concreta Pessoa, Empresa, BarracaNaFeira, Igreja, Ong
ficaria mais fácil de migrar a classe em outra regra de negócio, pois esses objetos Pessoa, Empresa, Barraca, vão existir no mundo
independente de conceitos
Ops. Pera ai:
pensei que tendo uma classe concreta Pessoa, Empresa, BarracaNaFeira, Igreja, Ong ficaria mais fácil de migrar a classe em outra regra de negócio
Errado. BarracaNaFeira, Igreja, Ong é um atributo de uma classe empresa! Tipo uma empresa pode ter uma atributo chamado de tipo de empresa que vai dizer se ela é uma barrarca uma ong ou igreja. Se não você vai ter trocentas mil classes…
ta parecendo que é mais simples mesmo Pessoa Jurídica extender de Pessoa.
Isso faz sentido, como disse, se você tiver mais classes que herdem de pessoa, ou seja que compartilhem o mesmo comportamento.
B
Bruno_Reis
//Para saber o tipo de clienteif(Cliente.getPessoa().tipoDePessoa()==TipoDePessoa.PJ)Cliente.getPessoa().getCNPJ();
Xandy, obrigado mais uma vez, vou esquecer aquela abstração com “trocentas” classes, rs valeu
tem como mostrar essa enumeração sendo criada na classe genérica Pessoa?
por favor, tem como mostrar isso de uma forma mais completa?
x111
Bruno Reis:
x@ndy:
Nessa classe implementaria um metodo abstrato chamado tipoPessoa, que retornaria o valor de uma Enumeração que listaria os tipos de Pessoas. (PF, PJ, Produtor Rural, etc.). Esse metodo seria implmentado nas classes que herdam de Pessoa de modo que as classes que utilizam a classe Pessoa não teriam que fazer um instanceof para saber com qual classe estão lidando.
O unico comportamento que utiliza polimorfismo seria realmente o metodo de retorno tipoPessoa.
//Para saber o tipo de clienteif(Cliente.getPessoa().tipoDePessoa()==TipoDePessoa.PJ)Cliente.getPessoa().getCNPJ();
Xandy, obrigado mais uma vez, vou esquecer aquela abstração com "trocentas" classes, rs valeu
tem como mostrar essa enumeração sendo criada na classe genérica Pessoa?
por favor, tem como mostrar isso de uma forma mais completa?
Uma coisa que pensei sobre vários papeis, não sei se era isso que você queria representar, mas nesse caso, um cadastro pode ser compartilhado entre clientes e fornecedores, ou seja, uma pessoa, pode ser um cliente ou um fornecedor ou os dois ao mesmo tempo, assumindo assim vários papeis!
B
Bruno_Reis
Xandy, obrigado mais uma vez
escrevi este código conforme você me indicou
@Entity@Table(name="pessoa")@Inheritance(strategy=InheritanceType.SINGLE_TABLE)publicclassPessoaimplementsSerializable{@Id@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="gen_pessoa_id")@SequenceGenerator(name="gen_pessoa_id",sequenceName="seq_pessoa_id",initialValue=1,allocationSize=1)@Column(name="id")privateIntegerid;@OneToMany(mappedBy="pessoa",cascade=CascadeType.ALL,fetch=FetchType.LAZY)privateList<Imovel>imovels;//aqui uma Pessoa física ou jurídica, está pertencida a um Cliente@OneToOne(mappedBy="pessoa",cascade=CascadeType.ALL,fetch=FetchType.LAZY)privateClientecliente;//métodos de acesso omitidos
@EntitypublicclassPessoaFisicaextendsPessoa{@Column(name="nome",length=20)privateStringnome;@Column(name="sobre_nome",length=30)privateStringsobreNome;@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)@JoinColumn(nullable=false,name="certidao_nascimento_id")privateCertidaoNascimentocertidaoNascimento;@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)@JoinColumn(nullable=false,name="cpf_id")privateCpfcpf;@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)@JoinColumn(nullable=false,name="rg_id")privateRgrg;//métodos de acesso omitidos}
@Entity@Table(name="cliente")publicclassClienteimplementsSerializable{@Id@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="gen_cliente_id")@SequenceGenerator(name="gen_cliente_id",sequenceName="seq_cliente_id",initialValue=1,allocationSize=1)privatelongid;@Column(name="limite_credito")privatedoublelimiteCredito;//um Cliente possui uma Pessoa que pode ser Física ou Jurídica@OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)@JoinColumn(nullable=false,name="pessoa_id",referencedColumnName="id")privatePessoapessoa;//métodos acesso omitidos}
quando inicio meu crud
public PessoaGUI() {
initComponents();
emf = Persistence.createEntityManagerFactory("SisComIntecon");
em = emf.createEntityManager();
em.getTransaction().begin();
List<PessoaFisica> pessoas = null;
try {
pessoas = em.createQuery("SELECT p FROM Pessoa p").getResultList();
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
}
model = new PessoaTableModel(pessoas);
tabelaPessoa.setModel(model);
this.setSize(700, 460);
}
O Hibernate está trazendo o Cliente, o Vendedor, o Fornecedor, também, sendo que eu não pedi, e as anotações estão como FetchType.LAZY
Os objetos Cliente, Fornecedor, Vendedor, estão fazendo referência à superclasse Pessoa
sendo que estou instanciando a subclasse PessoaFisica.
há algum problema neste código?
x111
Bruno Reis:
publicclassPessoaimplementsSerializable{//aqui uma Pessoa física ou jurídica, está pertencida a um Cliente@OneToOne(mappedBy="pessoa",cascade=CascadeType.ALL,fetch=FetchType.LAZY)privateClientecliente;}
Um problema que vejo é aqui a Pessoa não deve conhecer o Cliente. Ela é utlizada pelo cliente e pelo fornecedor, mas não deve conter uma referencia para eles.
Outro problema que eu vi é aqui:
O CPF, RG, etc devem ser Objetos Valor (Value Objects). É natural querer separar, mas isso acarreta em muitos joins, o que diminiui o rendimento enormemente, alêm do fato de que não faz sentido ele ser uma entidade (até hoje eu não encontrei motivo para isso)!
Outra coisa que vi é aqui:
Bruno Reis:
public PessoaGUI() {
initComponents();
emf = Persistence.createEntityManagerFactory("SisComIntecon");
em = emf.createEntityManager();
em.getTransaction().begin();
List<PessoaFisica> pessoas = null;
try {
pessoas = em.createQuery("SELECT p FROM Pessoa p").getResultList();
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
}
model = new PessoaTableModel(pessoas);
tabelaPessoa.setModel(model);
this.setSize(700, 460);
}
Você esta fazendo uma consulta para listar as pessoas, fora da classe pessoa! Isso é ruim, sua classe pode ser uma classe "anêmica", ou seja uma classe que funciona apenas como estrutura de dados e não aprensenta nenhum comportamento! Isso é péssimo, pois espalha lógica do dominio por todo o sistema! Já imaginou em quantos lugarares você pode querer listar todas as pessoas?
O ideal é que tu colocasse um método estático dentro da classe Pessoa que realiza-se esta busca!
Para saber mais sobre classes anêmicas sugiro que leia este post e esse do Shoes
mas no mundo real uma pessoa física não tem uma certidão de nascimento?
Pelo que estou percebendo, não devemos seguir estritamente, ao pé da letra o mundo real. Devemos pensar em performance, simplicidade? Estou certo?
Naquele texto lá com o título de Fantoches, está dizendo que não devemos incluir a lógica do domínio dentro de apenas um comportamento de um objeto porque com isto, estaremos programando de forma procedural. Que os métodos do objeto tem que ser “magros”.
Diz que cada objeto tem a sua responsabilidade, deve dizer respeito, resolver problemas relativos a si próprio. E que devo escrever o sistema sempre estando bem perto da realidade, do mundo real.
Estou meio confuso nesta questão. Seguir exatamente como as coisas funcionam no mundo. Ou, modificar as coisas do mundo para escrever o software.
Não tenho experiência nenhuma em OO.
Xandy
Agradeço muito por me responder.
Muito obrigado mesmo!
B
Bruno_Reis
realmente, parece não ter sentido criar um monte de classes que não farão nada (VO, BO)
que só servirão como repositório de dados e irão gerar muitos JOINS e muita manipulação de código sem sentido
para que criar a classe CertidaoNascimento se ela não vai resolver nada. Não é um sistema de Gestão de Cartórios de Registro Civil.
Para que criar a classe Celular extends Telefone se o sistema não é para ser aplicado na indústria de projetos de celulares. Qual problema de projeto, a ser resolvido sobre um determinado aparelho?
Para que criar uma classe RG, e CPF se não há nenhum problema a ser resolvido quanto a esses documentos? Não é um programa da Secretaria de Seg Pública, nem da Receita Federal.
O que você quis dizer é que o CPF e RG precisam ser objetos anêmicos VO. Aqueles que não tem comportamento?
Ou, que esses que eu escrevi já são VO e devem ser evitados?
Deverei escrever CPF e RG e demais documentos como atributos String do objeto PessoaFísica?
Ops, nenhum dos dois! Essa confusão ocorre devido a uma confusão nos nomes dos padrãoes VOs na verdade são TO (Transfer Objects), o VO foi renomeado para TO, justamente devido a essa confusão, mas muita gente ainda faz uso deles! Para saber mais de uma lida neste post do Shoes!
Objetos valor tem comportamento e não tem nada haver com os VOs clássicos! Um exemplo é o CPF, pois você pode validar o CPF, não permitido que seja cadastrado um CPF inválido, o mesmo se aplica a Certidão de Nascimento no qual seria obrigado o cadastro do nome da Mãe, por exemplo.
O que caracteriza um objeto valor é o fato dele existir somente se o objeto pai existir! Ele é persitido junto com o objeto a que ele pertence! Se esse objeto deixar de existir o objeto valor também deixará de exisitir! Um exemplo é a certidão de nascimento de uma pessoa ou CPF! Se a pessoa morrer não faz mais sentido que esses objetos ainda existam pois eles pertenciam aquela pessoa e não podem ser aproveitados por outra.
Pode se dizer que o objeto valor é parte de uma pessoa!
Em termos de persistência ele pode (pra não dizer deve) ocupar a mesma tabela do objeto a que ele pertence!
Agora deve se tomar cuidado com Objetos Valor! Nem sempre eles são o que parecem ser, depende muito do dominio da aplicação! Para um cadastro de pessoa física, faz sentido o CPF ser um Objeto Valor, agora se você estiver trabalhando na Receita Federal não faz o menor sentido! Na receita federal poderia ser até o contrário o CPF seria uma instancia e a pessoa poderia ser o Objeto Valor!
Quando a objetos anêmicos, muitas vezes você os encontrára e nem sempre isso é ruim. Por exemplo um objeto Telefone, essa uma classe na qual dificilmente existe um comportamento, mas é uma classe necessária para realizar a separação de responsabilidades!
realmente, parece não ter sentido criar um monte de classes que não farão nada (VO, BO)
que só servirão como repositório de dados e irão gerar muitos JOINS e muita manipulação de código sem sentido
para que criar a classe CertidaoNascimento se ela não vai resolver nada. Não é um sistema de Gestão de Cartórios de Registro Civil.
Para que criar a classe Celular extends Telefone se o sistema não é para ser aplicado na indústria de projetos de celulares. Qual problema de projeto, a ser resolvido sobre um determinado aparelho?
Para que criar uma classe RG, e CPF se não há nenhum problema a ser resolvido quanto a esses documentos? Não é um programa da Secretaria de Seg Pública, nem da Receita Federal.
É um simples sistema de vendas.
é preferível fazer assim não é?
temos que cassar então os VOs ou BOs, DTOs?
obrigado meu amigo, se puder comentar mais
vai me ajudar muito
Com certeza não! Essas classes são importantes para separação de responsabilidade! Agora com certeza uma Classe celuar que extende uma classe Telefone é muito preciosismo. Na verdade isso seria um atributo da classe telefone!
B
Bruno_Reis
Objeto valor é então um objeto acessório, que depende de um principal.
Então, em relacionamentos 1-1 não tem problema eu criar classes CPF, RG, CertidaoNascimento, desde que eu persista embutido em na mesma tabela Pessoa. Nâo vai gerar joins.
Se eu excluir a Pessoa do banco, já vai se embora suas classes dependentes.
Como você disse acima, neste artigo do Shoes “grandes gordas e sem sentido” diz que é recomendável criar tantas classe necessárias (quanto mais, mais separação de código, mais magrinhas ficam) de acordo com o negócio do cliente.
Para que quando o cliente pedir alterações, bastamos entender a mudança ocorrida no negócio dele. E mudarmos ou criarmos novas classes magrinhas.
É isso?
Posso continuar com minhas classes CPF, RG, Certidao, desde que sejam embutidas na tabela pessoa do banco?
B
Bruno_Reis
Acho que entendi. A classe tem a função de existir se tivermos um problema a ser resolvido.
Alocamos a responsabilidade a cada objeto.
x111
Bruno Reis:
x@andy:
Um exemplo é o CPF, pois você pode validar o CPF, não permitido que seja cadastrado um CPF inválido, o mesmo se aplica a Certidão de Nascimento no qual seria obrigado o cadastro do nome da Mãe, por exemplo.
Acho que entendi. A classe tem a função de existir se tivermos um problema a ser resolvido.
Alocamos a responsabilidade a cada objeto.
Sim, mas entendeu o conceito de Objeto Valor?
B
Bruno_Reis
Objeto valor não é um objeto acessório que depende do original?
B
Bruno_Reis
perdão
que depende da existência do Principal
o Principal deixando de existir, o Acessório também deixa
é parecido com uma agregação por composição?
B
Bruno_Reis
o que você quis dizer é que
se há um problema a ser resolvido na minha aplicação relativo a Cpf, o objeto pode resolver por que é responsabilidade dele fazer isso
se há um problema a ser resolvido quanto a Certidão de Nascimento, posso criar uma classe para fazer isso?
e a classe Imóvel, por exemplo
Endereço é um Objeto Valor de Imóvel, ao persistir, a classe Endereço pode ser Embedded de Imovel?
exclui um imóvel, excluo também seu endereço sem saber
x111
Não só pode como deve. Uma regra de programação basica é “Um método uma responsabilidade!”, Se um método faz a leitura de um arquivo ele não deve fazer a escrita também. Todos sabemos como fica confuso colocar tudo em um único metodo. A mesma regra se aplica as Classes. Cada classe deve ter uma unica responsabilidade. A composição de objetos, seja com objetos valor ou com referencia a objetos, faz com que a responsabilidade seja distribuida de forma a não sobrecarregar uma classe e permitidno o reaproveitamento de código!
Bruno Reis:
e a classe Imóvel, por exemplo
Endereço é um Objeto Valor de Imóvel, ao persistir, a classe Endereço pode ser Embedded de Imovel?
exclui um imóvel, excluo também seu endereço sem saber
Ai depende do dominio da aplicação! Uma classe endereço pode ser um objeto valor ou uma instancia! Tudo depende da forma como a classe vai ser usada!
Ficou confuso não? Vamos a um exemplo.
Imagine uma pizzaria. Para o sistema de entregas dessa pizzaria é baseado no endereço de entrega! Em um determinado endereço pode-se ter varios clientes vinculados e um cliente pode ter diversos endereços vinculados a ele! Nesse caso o conceito de objeto valor não faz sentido pois ao excluir um endereço não queremos excluir os clientes e vice versa! Nesse caso cada endereço e cliente são instancias. Agora em um loja virtual, pode ser diferente! Um endereço pode ser um objeto valor. Mesmo que dois clientes diferentes ocupem o mesmo imóvel, cada cliente tera o seu próprio endereço! Digamos que nesse dominio exista um objeto Encomenda que possua também um endereço e queremos que mesmo que o endereço do cliente mude o da encomenda continue o mesmo devido a rastreabilidade da encomenda. Nesse caso, Endereço continua sendo um VO, só que pertencente a encomenda e não ao cliente.
Aqui tem uma discussão sobre objeto valor bem interessante, deixando a trolice de lado claro
B
Bruno_Reis
rapaz, pensei que estava progredindo devagarinho,
tô lascado
to vendo que essa coisa de OO é muito difícil
um pneu é de borracha mas se for de madeira também está bom
um sorvete deve ser comido gelado mas, se estiver quente, é o ideal
não existe (de repente, ainda bem) um caminho linear a ser seguido. É vertical, é centro, você está no centro. Pode ir para o Norte, que você vai encontrar. Pode ir para o Sul, que lá está o que procura, no Leste é o caminho. No Oeste, está perto. rsrsrsrs
sua ajuda está sendo ótima para uma melhor visualização
Tem como um objeto não ser uma instância?
Como trazer os dados de um objeto valor?
Como uma Nota Fiscal vai ter uma cópia do objeto Cpf se ela não tem esse atributo? Não deveria ter.
Cpf é um atributo de pessoa, não de Nota Fiscal, Pedido, Contrato.
Pensei em criar uma classe para Imovel
publicclassPessoa{@OneToManyprivateList<Imovel>imovelList;}@EmbeddablepublicclassEndereco{privateStringlogradouro;privateStringnumero;privateStringbairro;}publicclassImovel{@EmbeddedprivateEnderecoendereco;privateTipoImoveltipoImovel;//poderia ser uma classe valor}
Escrevi isso baseando no cenário “uma pessoa possui vários imóveis”
Posso escrever o mesmo código para o cenário “uma pessoa ocupa vários imóveis”
Se várias pessoas ocupam um ou mais imóveis, não poderia ter uma classe associativa ContratoAluguel, ou MoradiaFamiliar para dizer por exemplo que João e Maria são filhos de José e ocupam um ou mais imóveis ao mesmo tempo.
x111
Ops, falha minha… rsrss… na verdade queria dizer entidade e não instancia.
Como o objeto valor não possui “identidade própria” (nada haver com id do banco de dados) ele só pode ser obtido a partir do objeto a que ele pertence ou seja no casso CPF só pode ser obetido através da classe pessoa ou da classe nota fiscal por exemplo!
Esse foi um exemplo. Em alguns casos é necessário lançar na nota fiscal o CPF do cliente! Então o CPF passa a ser um atributo tanto da pessoa como da Nota Fiscal. O que eu queria dizer com esse exemplo é que um objeto valor pode ser compartilhado, mas não o mesmo objeto e sim uma cópia deste objeto.
Aparentemente nesse “cenário” (eu prefiro a palavra dominio) faz sentido o endereço ser um objeto valor.
Você deve tomar cuidado com duas coisas!
1)Objetos valor não podem ser alterados fora da entidade a que eles pertencem! Você deve sempre passar uma cópia do objeto valor e não uma referencia!
No caso do imóvel por exemplo. Se você “compartilhar o endereço” de um imóvel com uma pessoa não faça isso com uma referencia e sim faça uma copia do objeto e passe essa copia para o objeto pessoa. Se a pessoa alterar o seu “endereço” ela não vai alterar o endereço do imóvel.
2)Um objeto valor em JPA(@Embeddable) nem sempre é apropriado. Voce pode ter um objeto valor usando join. Isso faz sentido em objetos valor que são muito compartilhados e que podem sofrer muitas mudanças. Um exemplo pode ser o endereço. Caso ele sofra muitas alterações você vai ter que fazer isso em diversas tabelas e isso pode ser ruim, nesse caso o objeto valor pode ocupar uma outra tabela e você faz um join para trazer o objeto. Outro caso é quando temos uma referencia de 1:n ou seja, uma pessoa pode ter n endereços, o que obriga a utilização de uma segunda tabela. Mas mesmo assim a classe endereço para o “dominio” continua sendo um objeto valor e ao realizar uma copia do objeto, você não copia a ID desse objeto, mas copia todos os outros atributos pertencentes a ele.
Bom, espero que tenha sido claro.
B
Bruno_Reis
Como fazer isso?
Pessoa vai ter atributo endereço? Imóvel também vai ter atributo endereço? Nota Fiscal vai ter atributo endereço? Romaneio vai ter atributo Endereço?
Pode ser assim? É que no livro que li, do Eduardo Bezerra, diz que os atributos não podem ser repetidos em diversas classes.
Como não fazer com referência (composição)? Como fazer uma cópia do objeto?
B
Bruno_Reis
Nota Fiscal pode ter um atributo CPF?
Cpf não é atributo de Pessoa?
x111
Bruno Reis:
x@andy:
No caso do imóvel por exemplo. Se você “compartilhar o endereço” de um imóvel com uma pessoa não faça isso com uma referencia e sim faça uma copia do objeto e passe essa copia para o objeto pessoa.
Como fazer isso?
Pessoa vai ter atributo endereço? Imóvel também vai ter atributo endereço? Nota Fiscal vai ter atributo endereço? Romaneio vai ter atributo Endereço?
Pode ser assim? É que no livro que li, do Eduardo Bezerra, diz que os atributos não podem ser repetidos em diversas classes.
Como não fazer com referência (composição)? Como fazer uma cópia do objeto?
Acho que você não entendeu o conceito de Objeto Valor ainda! Vamos pelo inicio. Em um sistema persistente você pode der basicamente dois tipos de classes. Entidades e Objetos Valor Entidade é um objeto persistente que possui uma identidade definida. Como identidade digo algo que caracterize esse objetos de outros objetos persistentes. No caso do objeto pessoa, por exemplo, Pode haver duas pessoas com nomes iguais, como identificar uma pessoa de outra? Deve ser definido uma identidade para cada pessoa que seja único para cada classe. Ao comparar-mos por exemplo duas pessoas usando “equals” eu vou comparar apenas os ids dessas pessoas. Isso que vai dizer se elas são diferentes ou não. Objeto Valor é um objeto desprovido de identidade, normalmente ele está relacionado a outro objeto mas isso não é uma regra. Como objetos valor não tem identidade eles não podem ser rastreados ou armazenados sem que seja por intermedio de outro valor. Objetos valor não podem ser alterados fora do objetos a que ele pertecem, por que isso gera uma serie de problemas. Por exemplo: Imagine um sistema web em que existam duas classes Cliente e Nota Fiscal. A classe cliente possui um endereço e nota fiscal possui um endereço também. Digamos que o cliente realize varias compras. O sistema passa para nota fiscal uma referencia para objeto endereço do cliente e as notas são emitidas. Até ai tudo bem. Mas o que acontece se o cliente atualizar seu endereço? O endereço de todas as notas já emitidas também será atualizado e isso invalidaria nota pois a mesma já foi emitida. Nesse caso deve ser compartilhado uma copia do endereço e não uma referencia!
Para realizar a copia você pode sobrescrever a função clone, ou pode criar uma função copy, por exemplo, que realiza cria um novo objeto passando como parametro todos os objetos. Eu não conheço um padrão para isso.
x111
Bruno Reis:
x@andy:
CPF só pode ser obetido através da classe pessoa ou da classe nota fiscal por exemplo!
Nota Fiscal pode ter um atributo CPF?
Cpf não é atributo de Pessoa?
Tudo depende do dominio de sua aplicação! Se a receita do seu estado exigir (ou seu cliente), você pode ter que colocar esse atributo na nota ou você pode passar para nota uma a propria classe pessoa. Mas nesse caso a classe pessoa passa ser um objeto valor da nota fiscal! Isso pq alterações feitas em pessoas não o pode ser replicada para nota.
B
Bruno_Reis
Xandy
acredito que entendi
Objeto Valor é um objeto persistente, sem identidade, totalmente dependente, não pode ser instanciado sozinho. Não precisa ser Embeddable.
Se não precisa ser Embeddable. É possível utiliza-lo em relacionamentos?
O objeto não tem id.
A tabela dele que vai ter que ter uma FK então?
x111
Bruno Reis:
Xandy
acredito que entendi
Objeto Valor é um objeto persistente, sem identidade,totalmente dependente, não pode ser instanciado sozinho. Não precisa ser Embeddable.
Não necessáriamente. Voce pode instanciar um Objeto Valor, a grande característica é mesmo a falta de identidade. O que você não pode fazer é armazena-lo sozinho no banco de dados.
Bruno Reis:
Xandy
Se não precisa ser Embeddable. É possível utiliza-lo em relacionamentos?
Não. Objetos valor não pode ser utilizado em relacionamentos, mas você pode compartilhar uma cópia do objeto valor com outro objeto.
Bruno Reis:
Xandy
O objeto não tem id.
A tabela dele que vai ter que ter uma FK então?
Na maioria dos casos sim. Mas a arquitetura do banco de dados nem sempre permite isso! Um exemplo é o endereço, se você tiver varias classes que usam o endereço tu terias que ter varias tabelas iguais, uma para cada objeto que faz referencia a ele. Seu DBA pode não achar isso ideal e te dizer o certo é ter uma tabela só para endereço ao invés de varias. Ai surge o problema, pois não é possivel ter chaves estrangeiras para tabelas diferentes! Então nesse caso você é obrigado a colocar uma chave primaria que seja uma sequence ou algo parecido de forma a recriar o objeto. Esse id do objeto é apenas uma referencia para uma posição na tabela do banco de dados e não representa a identidade do seu objeto valor. Se você for sobrescrever “equals” deve desconsiderar a id do banco!
Se tivermos dois objetos endereços, por exemplo, eles serão iguais se e somente se todo os seus atributos forem iguais. No caso de entidades elas são iguais se as duas tiverem a mesma identidade!
Isso é um dos problemas no mapeamento objeto relacional.
B
Bruno_Reis
Mas como assim, se eu tenho um List de Pessoa, não terei um grupo de pessoa[0], pessoa[1], pessoa[2], etc?
em List essa classe não é a mesma de
public class Pessoa {
esses código são todos emprestados de apostilas de java como a K19 e de exemplos daqui do GUJ
x111
Desculpe pela demora em responder, mas os últimos dias foram corridos.
Bem vamos lá,
O que eu quis dizer é que você está fazendo a busca pelas pessoas fora da classe pessoa:
public PessoaGUI() {
initComponents();
emf = Persistence.createEntityManagerFactory("SisComIntecon");
em = emf.createEntityManager();
em.getTransaction().begin();
List<PessoaFisica> pessoas = null;
try {
pessoas = em.createQuery("SELECT p FROM Pessoa p").getResultList();
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
}
Nesse construtor de uma outra classe você esta carregando todas as pessoas! E isso é que esta errado, pois você vai precisar realizar esta listagem em outros lugares, então daqui a pouco você vai ter esse código replicado em mil lugares e ai, quando for necessário alterar já viu o problema né! Para evitar isso existem três formas:
Criar um DAO e obter a pessoa a partir dai, mas isso não é o ideal, pois você acaba tendo um objeto burro pessoa, que não faz nada e tem duas classes, uma para buscar e outra que representa os dados então isso nos leva a segunda forma de persisitir as pessoas no banco de dados:
Criar um Active Record. O padrão active record faz com que os dados e a persistencia destes ocupem a mesma classe ou seja você vai ter uma classe Pessoa e nessa classe vai ter os metodos Pessoa.ListarTodas(), pessoa.atualizar, pessoa.excluir().
Como exemplo temos:
public Pessoa{
public static Pessoa listarTodas(){
emf = Persistence.createEntityManagerFactory("SisComIntecon");
em = emf.createEntityManager();
em.getTransaction().begin();
List<PessoaFisica> pessoas = null;
try {
pessoas = em.createQuery("SELECT p FROM Pessoa p").getResultList();
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
}
return pessoas;
}
public void atualizar(){
....
}
public void excluir(){
....
}
}
Isso já e bom e pode ser usado tranquilamente, mas ainda não é o ideal, pois a classe pessoa não deveria saber nada sobre a persistencia dos dados. Isso não é de responsabildade dela e isso nos leva a forma ideal de fazer.
Criar um Repository para buscar os dados! O padrão repository faz a conexão entre a classe pessoa e os dados, dessa forma a classe pessoa não fica sobrecarregada!
Vamos a um exemplo:
public Pessoa{
private Static RepositorioPessoa repositorio;
...
public static Pessoa listarTodas(){
return repositorio.ListarTodasAsPessoas();
}
public void atualizar(){
repositorio.atualizar(this);
}
public void excluir(){
repositorio.atualizar(this);
}
}
...
public RepositorioPessoa {
public static Pessoa listarTodas(){
emf = Persistence.createEntityManagerFactory("SisComIntecon");
em = emf.createEntityManager();
em.getTransaction().begin();
List<PessoaFisica> pessoas = null;
try {
pessoas = em.createQuery("SELECT p FROM Pessoa p").getResultList();
em.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
em.getTransaction().rollback();
}
return pessoas;
}
public void atualizar(Pessoa pessoa){
...
}
public void excluir(Pessoa pessoa){
...
}
}
Agora você viu que a responsabilidade de listar as pessoas saiu da classe pessoa e passou para classe RepositorioPessoa! Note que se você quiser mudar a forma de perisistir os dados, digamos buscar os dados a partir de um arquivo XML, não necessita mexer na classe pessoa. Neste caso você pode criar uma nova classe, digamos RepositorioXML_Pessoa e em runtime decidir se vai usar essa ou a classe RepositorioPessoa. Sei que isso é raro de acontecer, mas exemplifica o o porque da separação de responsabilidade.
Com relação a utilização de exemplos, é sempre bom falar que são exemplos! Um exemplo de como trazer os dados, não quer dizer que devemos fazer em nosso sistema daquela forma. Se alguem me perguntar como faz para trazer os dados do banco usando JPA eu não vou falar para ele criar um repositorio, vou mostrar de forma prática como se faz. Cabe a cada um usar o exemplo da melhor forma, seja esse exemplo do GUJ, de uma apostila da Caelum ou de um livro dos Deitel.
B
Bruno_Reis
xandy
aí, essa classe Pessoa eu poderei instanciar diretamente dentro da classe JFrame do Swing para fazer um crud de Pessoas?
sei que não é correto misturar o domínio com a interface gráfica
mas, criar um controlador, ainda não dá pra mim não, rsrsr sou só curioso java, estou estudando sem professor, só com artigos e apostilas da net
vou estudar com calma sobre o Repositório
procurei aquele livro do Martin Fowler, Padrão de Arquitetura de Softwares Corporativos, tá em falta nas livrarias
você está me ajudando muito, sem ela, iria fazer uns códigos mirabolantes. Uma mistureba danada.
B
Bruno_Reis
ah, outra pergunta
nos relacionamentos unidirecionais OneToOne FetchType.LAZY, o Hibernate não carrega junto o objeto associado. Ou seja, executa o LAZY certinho.
Já nos relacionamentos bidirecionais @OneToOne(mappedBy = “objeto_pk”, fetch=FetchType.LAZY) o Hibernate ignorar o LAZY e traz indevidamente o objeto associado?
em OneToMany e ManyToOne tá funcionando direitinho, respeita o LAZY corretamente
Uso Hibernate + Eclipse Indigo
Muito obrigado!!!
x111
Bruno Reis:
xandy
aí, essa classe Pessoa eu poderei instanciar diretamente dentro da classe JFrame do Swing para fazer um crud de Pessoas?
sei que não é correto misturar o domínio com a interface gráfica
mas, criar um controlador, ainda não dá pra mim não, rsrsr sou só curioso java, estou estudando sem professor, só com artigos e apostilas da net
vou estudar com calma sobre o Repositório
procurei aquele livro do Martin Fowler, Padrão de Arquitetura de Softwares Corporativos, tá em falta nas livrarias
você está me ajudando muito, sem ela, iria fazer uns códigos mirabolantes. Uma mistureba danada.
Eu não recomendo o uso sem controlador, mas, para um simples CRUD você pode usar sem problemas. Caso você note esta sendo replicando código entre dois formulários diferentes pode refatorar o código para um controlador. Aqui tem uma discusão minha como o Vini Godoy sobre a utilização de controlador em aplicação desktop, onde eu coloco meus argumentos para a utilização dele e o vini os dele para não utilização. Pelo jeito seu caso se enquadra na não utilização.
Recomendo também que você leia o livro Domain Driven Design do Eric Evans. O livro é muito bom embora ele seja um pouco prolixo.
Se não leu ainda, aproveite e leia também o livro Use a Cabeça! Padrões de Projeto.
x111
Bruno Reis:
ah, outra pergunta
nos relacionamentos unidirecionais OneToOne FetchType.LAZY, o Hibernate não carrega junto o objeto associado. Ou seja, executa o LAZY certinho.
Já nos relacionamentos bidirecionais @OneToOne(mappedBy = “objeto_pk”, fetch=FetchType.LAZY) o Hibernate ignorar o LAZY e traz indevidamente o objeto associado?
em OneToMany e ManyToOne tá funcionando direitinho, respeita o LAZY corretamente
Uso Hibernate + Eclipse Indigo
Muito obrigado!!!
Bom, não posso ajuda-lo nesse caso, sugiro que coloque isso como um novo tópico!
Olá pessoal. Me interessei por este tópico… já perdi bastante tempo pensando na fórmula perfeita para esse lance de pessoa física/jurídica,
procurando algo q fosse simples e flexível.
Alguns meses atrás, precisei implementar isso e comecei a matutar várias situações, com herança, composição,
usando padrão de Roles, etc… (coisas q comentaram aqui no post também)
Por fim, achei que o q me renderia menos tempo de trabalho seria algo mais simplista:
não me lembro se criei uma classe abstrata ou se foi uma interface chamada Documento,
e outras 2 classes concretas, sendo Cnpj e Cpf, respectivamente, que herdam Documento.
Neste caso, clientes e fornecedores poderiam ter cadastro de PF ou PJ.
Bem, foi só isso. No meu caso, resolveu todo o problema e achei que encaixou bem em várias situações.
Tentem imaginar aí o que poderia ser feito apartir daí, se resolveria o problema de vcs e tals.
Não digo que é correto ou não, mas foi algo q funcionou bem pra mim.