Eu crio no meu código uma classe “Aprendiz”. Ele tem 1 trilhão de propriedades, entre elas, pro exemplo, “Pontos_de_Vida”, “Dano” e “Defesa”, tal que essas propriedades irão sendo modificadas constantemente no decorrer do jogo.
Daí, o jogo vai passando e num determinado momento o “Aprendiz” se tornará um “Guerreiro” (Guerreiro é uma classe filha de Aprendiz)
Então, como eu faço pra criar um novo Guerreiro herdando as propriedades (que estavam modificadas) desse Aprendiz ?
Tipo assim: Eu quero “remodelar” esse aprendiz, transfomando-o em um “Guerreiro”, mas mantendo suas “1 trilhão” de propriedades com o mesmo valor, somente ganhando as novas propriedades do “Guerreiro” (que ja estarão setadas com um valor default).
Se você tem uma instância ativa de Aprendiz você vai ter que realmente copiar os dados para a instância de Guerreiro que você acabou de criar. A não ser que todos os aprendizer se tornem Guerreiro um dia, então você poderia já ter uma instância de Guerreiro, mas acessada via uma intância de aprendiz, e em um terminado momento você fazia um casting para uma referência do tipo Guerreiro.
Teria algo assim
Aprendiz a = new Guerreiro();
//adicionar os dados para aprender chamando os métodos em a
a.fazCoisasDeAprendiz();
//recebe um evento que transforma aprendiz em guerreiro
Guerreiro g = (Guerreiro)a;
g.fazCoisasDeGuerreiro();
Se não pudermos afirmar que todos Aprendiz se tornará um Guerreiro você pode ter que um Guerrero só pode ser criado se receber uma instância de aprendiz, e copiar estes dados para Guerreiro.
public class Guerreiro extends Aprendiz {
//variaves de guerreiro
public Guerreiro(Aprendiz a) {
setNome(a.getNome()); // metodo da classe Aprendiz
//outros metodos de aprendiz
setTipo("Guerreiro");
}
//metodos de guerreiro
}
Algumas linguagens permitem que você altere dinamicamente a classe de um objeto já existente.
Em Java, no entanto, isso infelizmente não existe.
A forma mais estúpida de fazer isso é ter um construtor na classe Guerreiro que recebe um objeto da classe Aprendiz, e copie os campos adequados. O problema, obviamente, é que você vai ter de ficar caçando no seu programa todos os pontos em que esse tal objeto é referenciado, e trocar por uma referência para o novo objeto. Então nem sempre é uma alternativa.
Outra forma é assumir que Guerreiro, Aprendiz etc. são todos Jogadores, e ter apenas objetos da classe Jogador. Entretanto, como você quer ter implementações diferentes para os métodos “lutar”, etc, o que você pode fazer é ter várias classes (HabilidadesGuerreiro, HabilidadesAprendiz etc) que são implementações desses tais métodos. Você então põe um atributo na sua classe Jogador que é uma instância dessa classe Habilidades.
Ao você alterar um jogador de Aprendiz para Guerreiro, você altera só esse atributo.
enum Fase { APRENDIZ, GUERREIRO, ..... };
interface Habilidades {
void lutar (Jogador j);
}
class HabilidadesGuerreiro implements Habilidades {
public void lutar (Jogador j) { .... }
}
class HabilidadesAprendiz implements Habilidades {
public void lutar (Jogador j) { .... }
}
class Jogador {
private Habilidades hab;
public void lutar () { hab.lutar (this); }
...
public void evoluiFase (Fase f) {
switch (f) {
case APRENDIZ: hab = HabilidadesAprendiz.getInstance(); break;
case GUERREIRO: hab = HabilidadesGuerreiro.getInstance(); break;
...
}
}
}
...
Jogador j = new Jogador (Fase.APRENDIZ); // isto faz com que suas habilidades sejam as de um aprendiz
j.lutar(); // j.lutar chama hab.lutar (j); com hab sendo uma instância de HabilidadesAprendiz
j.evoluiFase (Fase.GUERREIRO);
j.lutar(); // j.lutar chama hab.lutar (j); com hab sendo uma instância de HabilidadesGuerreiro
...