Modo correto Abstração de Pessoas

Olá Pessoal,

Estou com um problema de abstração que na teoria é simples mas na pratica estou tendo sérios problemas para implantar.

Tenho que abstrair Pessoas, Pessoas Físicas, Pessoas Jurídicas e Usuários por modos de herança, até ai tudo bem, todo o CRUD dos objetos devem ser feitos classes especificas para tratar cada objeto. Minha duvida é quando eu quiser buscar todas as pessoas? Como deveria ser a classe para suportar os dois tipos de pessoas para que possa trabalhar no model do JTable? Digo pois teria que fazer um busca por pessoas Físicas, depois por Jurídicas e unificar a pesquisa.

Meu modelo:
Pessoas —> Pessoas Físicas —> Usuários
Pessoas —> Pessoas Júridicas

** Classe Pessoas é abstrata não podendo ser instanciada.**

A duvida chegou quando tentei exibir todas as pessoas Físicas e Jurídicas em uma unica JTable do Java.

Uma coisa é certa, você terá uma lista de pessoas para ser usada na jtable (List<Pessoa>).Você deve executar as consultas de pessoa física e jurídica e retornar tudo nessa única lista. A questão é fazer a tratativa corretamente na jtable.

Uma pergunta, quais dados você irá apresentar na jTable?

Olá Lucas,

Então, eu pretendo exibir na JTable dados especificos de cada tipo de pessoa como por exemplo, FAX, CNPJ, INSCRIÇÃO MUNICIPAL, ESTADUAL, DATA DE NASCIMENTO.

Se eu fizer uma List<Pessoa>, a Classe Pessoa não possui essas informações, eu teria que cria um objeto PessoaFisica e PessoaJuridica dentro de Pessoa, isso fará que o sistema fique recursivo, pois PessoaFisica já herda toda a classe pessoa, não daria certo. É exatamente esse o problema que estou tendo.

Alguma outra ideia?

Montei um exemplo:

Classe Pessoa:

public abstract class Pessoa {

    private String nome;
    private String sobrenome;

    public Pessoa() {
        super();
    }
    
    public Pessoa(String nome, String sobrenome) {
        super();
        this.nome = nome;
        this.sobrenome = sobrenome;
    }

    // getters and setters
}

Classe PessoaFisica:

public class PessoaFisica extends Pessoa {
    
    private String cpf;
    
    public PessoaFisica(String nome, String sobrenome, String cpf) {
        super(nome, sobrenome);
        this.cpf = cpf;
    }
    
    // getters and setters
}

Classe Pessoa Jurídica:

public class PessoaJuridica extends Pessoa {
    
    private String cnpj;
    
    public PessoaJuridica(String nome, String sobrenome, String cnpj) {
        super(nome, sobrenome);
        this.cnpj = cnpj;
    }

    // getters and setters
}

Classe que representa o modelo da tabela PessoaTableModel:

import java.util.ArrayList;
import java.util.List;

import javax.swing.table.AbstractTableModel;

public class PessoaTableModel extends AbstractTableModel {
    private static final long serialVersionUID = 1L;
    
    private List<Pessoa> data = new ArrayList<Pessoa>();
    private String[] columnNames = {"Nome", "Sobremome", "CPF", "CNPJ"};
    
    private static final int NOME = 0;
    private static final int SOBRENOME = 1;
    private static final int CPF = 2;
    private static final int CNPJ = 3;
    
    public PessoaTableModel() {
        super();
    }
    
    public PessoaTableModel(List<Pessoa> pessoas) {
        super();
        this.data = pessoas;
    }

    @Override
    public int getRowCount() {
        return data.size();
    }

    @Override
    public int getColumnCount() {
        return columnNames.length;
    }
    
    public String[] getColumnNames() {
        return columnNames;
    }
    
    public String getColumnName(int col) {
        return columnNames[col];
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Pessoa pessoa = data.get(rowIndex);
        
        if(columnIndex == NOME) {
            return pessoa.getNome();
        } else if(columnIndex == SOBRENOME) {
            return pessoa.getSobrenome();
        } else if(columnIndex == CPF && pessoa instanceof PessoaFisica) {
            return ((PessoaFisica) pessoa).getCpf();
        } else if(columnIndex == CNPJ && pessoa instanceof PessoaJuridica) {
            return ((PessoaJuridica) pessoa).getCnpj();
        } else {
            return "-";
        }
    }
}

Classe que monta a janela principal para apresentar a JTable Janela:

import java.awt.HeadlessException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;

public class Janela extends JFrame {
    private static final long serialVersionUID = 1L;

    public Janela() throws HeadlessException {
        super("Janela");
        
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500, 500);
        setLocationRelativeTo(null);
        setVisible(true);
        
        initComponents();
    }

    private void initComponents() {
        getContentPane().setLayout(null);
        
        List<Pessoa> pessoas = new ArrayList<Pessoa>();
        pessoas.add(new PessoaFisica("Pessoa 1", "AAA", "111.111.111-11"));
        pessoas.add(new PessoaFisica("Pessoa 2", "BBB", "222.222.222-22"));
        pessoas.add(new PessoaFisica("Pessoa 3", "CCC", "333.333.333-33"));
        pessoas.add(new PessoaJuridica("Pessoa 4", "DDD", "44.444.444/0001-44"));
        pessoas.add(new PessoaJuridica("Pessoa 5", "EEE", "55.555.555/0001-55"));
        pessoas.add(new PessoaJuridica("Pessoa 6", "FFF", "66.666.666/0001-66"));
        
        JTable tabela = new JTable();
        tabela.setModel(new PessoaTableModel(pessoas));
        JScrollPane scroll = new JScrollPane();
        scroll.setViewportView(tabela);
        scroll.setBounds(5, 5, 475, 450);
        add(scroll);
    }
    
    public static void main(String[] args) {
        new Janela();
    }
}

E aqui o exemplo rodando:

1 curtida

Sensacional Lucas!!

Era exatamente esse o problema que eu estava tendo, não sabia que era possivel fazer um Casting igual esse do seu TableModel, de Pessoa Fisica para Pessoa. Na minha concepção, como Pessoa não tem os dados de Pessoa Física, isso iria ser pedido no Casting.

Uma ultima duvida, você acha que eu deveria ter esse mesmo nível de abstração no banco de dados ou simplesmente devo ter uma unica tabela para armazenar os dois tipos de Pessoa? Digo pois em uma base de 20k de registro de Pessoas, fazer muitos joins pode perder muito na eficiência da pesquisa.

Desde já, muitíssimo obrigado.