Estou tendo um problema com a implementação de uma herança em uma aplicação. Imaginemos o seguinte exemplo:
[code]
public class Pessoa{
String cpf;
String nome;
}
public class Usuario extends Pessoa {
String username;
String senha;
}[/code]
Meu problema é o seguinte: eu quero criar um objeto Usuario a partir de um objeto Pessoa. Como o java não faz downcasting automático, já tentei fazer um typecast com Usuario, mas dá uma ClassCastException.
Existe alguma forma dessa “conversão” ser feita automaticamente ou eu tenho de implementar, na classe Usuario, algo que receba um objeto do tipo pessoa e o instancie?
O que eu realmente quero é por pura preguiça e conveniência…
Imaginem o seguinte, utilizando as classes acima (por preguiça eu não coloquei os getters nem setter, mas vamos imaginar que eles existem)
[code]Pessoa pessoa = new Pessoa();
pessoa.setNome(“José da Silva”);
pessoa.setCpf(“123”);
Usuario user = new Usuário();
user.setNome(pessoa.getNome());
user.setCpf(pessoa.getCpf());
user.setLogin(“zedasilva”);
user.setSenha(“avlisadez”);[/code]
Na verdade, eu quero é mais ou menos isso… mas eu gostaria que, de alguma forma mágica, eu utilizasse o objeto pessoa pra criar uma instância de usuário…
Imaginem o caso, de repente, eu preciso modificar a classe pessoa e inserir mais um atriubuto, por exemplo, rg. Eu teria que refatorar meu código em todo lugar que eu fizesse essa transposição para que o rg fosse preenchido em usuário tb…
Não vejo, conceitualmente, muita barreira pra isso, pois um usuário é uma pessoa… então, deveria ser possível eu criar um a partir do outro…
Estou trabalhando num esquema de autenticação utilizando JAAS que eu desenvolvi. Funcionaria mais ou menos assim
Ele faria a autenticação em uma base qualquer e traria os dados da pessoa;
caso essa pessoa existisse em minha base de permissões, ele carregaria as permissões e instanciaria um usuário com a pessoa carregada;
caso não existisse, ele insere essa pessoa e cria permissões básicas, transformando ela num usuário.
Acontece que a classe usuário é apenas utilizada nesse contexto do login; eu tenho um método que me retorna uma pessoa da base de dados, que eu utilizo para verificar se ele existe ou não, e eu gostaria de reaproveitar esse método. Por isso da necessidade de eu transformar uma pessoa direto em um usuário.
Mas aí não fica meio estranho?
Um usuário é uma pessoa, não contém uma pessoa.
Não sei se seria conceitualmente correto carregar esse objeto dentro dele…
De qualquer maneira, essa é uma coisa meio chata da linguagem Java: um objeto não pode mudar de classe dinamicamente.
Outro dia alguém perguntou se ele podia promover um Aprendiz para Guerreiro ou outra coisa parecida (em um problema daqueles que temos de resolver, normalmente seria promover um Funcionario para Gerente ou um Gerente para Diretor).
Se você pudesse transformar um objeto de uma superclasse em um objeto de uma subclasse, apenas adicionando os atributos novos, resolveria problemas semelhantes ao seu.
[quote=paulodamaso]Entendi o q vc quis dizer, thingol.
Mas aí não fica meio estranho?
Um usuário é uma pessoa, não contém uma pessoa.
Não sei se seria conceitualmente correto carregar esse objeto dentro dele… [/quote]
E…se a gente assumir que o usuário (Usuario) não seja uma pessoa (Pessoa) e sim um papel que a pessoa desempenha; o exemplo do thingol não ficaria bacaninha?
Uma coisa que percebi é que se pudéssemos mudar a classe em tempo de execução isso resolveria alguns problemas de modelagem.
Um dos problemas é o seguinte: digamos que você tenha um objeto do tipo Aprendiz, que foi promovido a Guerreiro. (E tenha a hierarquia Jogador -> Aprendiz -> Guerreiro -> General -> Rei, por exemplo).
Ele tem alguns atributos adicionais (até aí tudo bem), mas o problema é que eu não posso simplesmente pegar o tal objeto do tipo Aprendiz e copiá-lo para um objeto do tipo Guerreiro, senão eu teria de ficar procurando TODAS as referências a ele no programa, para substituí-las por esse novo objeto (ou seja, você deveria poder morrer para ressuscitar , mas o problema é que, devido às referências, você não consegue morrer para poder ser substituído).
Como vocês viram, deve ser melhor separar essa parte do papel que um determinado objeto desempenha, e separá-lo em um atributo. Ou seja, há só uma classe Jogador, que não tem descendentes, mas há várias classes derivadas de Papel, por exemplo PapelAprendiz, PapelGuerreiro, PapelGeneral e PapelRei.
Quando você precisar promover um Jogador de aprendiz para guerreiro, você só altera o atributo Papel, com um objeto da classe adequada (PapelGuerreiro) contendo os atributos necessários para um guerreiro.
Ou seja, o conceito “É UM” da OOP é um pouco vago. Isso porque o verbo “SER” é bastante ambíguo em português.
Muitas vezes, o que ocorre é que um determinado objeto “DESEMPENHA O PAPEL DE” (em vez de “SER UM”); nesse caso, é necessário criar uma classe Papel, e fazer a classe ter um atributo do tipo Papel.
Se algo pode mudar de categoria durante seu tempo de vida (um funcionário ser promovido a gerente, ou ser rebaixado), então você tem esse caso de “desempenhar o papel de”.
Sendo aprendiz, não posso saber se é guerreiro ou não; sem guardar uma refencia de aprendiz, o guerreiro seria um guerreiro “do zero”, como se fosse criado naquele momento, com uma referência nova; o correto mesmo é esse guerreiro ter uma referência pra aprendiz, indicando qual aprendiz ele é.
Só que isso detona a herança, não? Digo assim, a herança vira uma coisa redundante; digamos que:
Usuario u= new Usuario();
u.getPessoa().getNome();
u.getNome();
O que me dá redundância e é conceitualmente errado. No caso, eu precisaria de um relacionamento de herança para o tratamento de um usuário como uma pessoa em certos lugares da aplicação.
public class Usuario extends Pessoa{
private String login;
private String senha;
public login();
}[/code]
Agora vem a cruel questão. Por ser uma pessoa, usuário não deveria ter acesso ao método validaCpf()? Certo, eu sei que ele precisaria ser protected para ser lido pelos descendentes da classe… então ele simplesmente deixa de existir quando fazemos a herança?
Chamando o metodo validaPessoa em uma instância da classe Usuario ele acharia o validaCpf?
Caso eu não possa modificar o validaCpf para protected (por exemplo, estou utilizando uma biblioteca do java), como fazer pra conseguir chamar esses métodos sem copiar código de implementação?