Decidir qual classe iniciar em tempo de execução

6 respostas
dedraks

Pessoal estou com a seguinte dúvida:

Tenho uma classe abstrata que define um método x qualquer.
public abstract class A1 {
    public abstract int getX();
}
Tenho 3 classes que implementam o método x.
public class B1 {
(...)
    public int getX() {
        return 1;
    }
(...)

public class B2 {
(...)
    public int getX() {
        return 2;
    }
(...)

public class B3 {
(...)
    public int getX() {
        return 3;
    }
(...)
}
No meu programa eu crio um objeto do tipo A1:
A1 meuobjeto;
Agora em tempo de execução eu preciso instanciar esse objeto com uma das classes filhas.
if (condicao qualquer) meuobjeto = new B1();
else if (outra condicao) meuobjeto = new B2();
else if (mais uma condicao) meuobjeto = new B3();
else meuobjeto = null;

Mas eu queria mesmo era saber o nome da classe assim:
Esse código é imaginário.
[code]

Essa é a forma correta de se fazer o que quero?

6 Respostas

V

Olá,

a sua pergunta ficou um pouco obscura, não entendi exatamente o que você quiz dizer com

"Mas eu queria mesmo era saber o nome da classe assim:
Esse código é imaginário.
"

ficaria mais fácil se você fosse mais claro, mas independentemente de qualquer coisa a forma correta de se implementar uma classe abstrata é extendendo ela. Então o seu código deverá ficar mais ou menos assim

public class B1 extends A1 {   
(...)   
    public int getX() {   
        return 1;   
    }   
(...)   
  
public class B2 extends A1 {   
(...)   
    public int getX() {   
        return 2;   
    }   
(...)   
  
public class B3 extends A1 {   
(...)   
    public int getX() {   
        return 3;   
    }   
(...)   
}
jcavictorio
Você pode instanciá-las utilizando a sintaxe:
A1 a1 = new B1();

Em tempo de execução o método chamado será o subscrito em B1 ou na subclasse que você estiver instanciando.

Você pode ainda tentar utilizar o operador instanceof :
A1 a1 = new B1();
		if(a1 instanceof B1){
			a1.getX();
			//faz algo
		}

Espero que ajude.

jcavictorio

Você pode ainda criar um metodo static que retorne A1, algo como:

static public A1 getInstance(EnumCondicao condicao){
	    	switch (condicao) {
			case B:
				return new B1();
				break;
			case C:
				return new C1();
				break;

			default:
				return null;
			}

E poderá utilizar a sintaxe:

A1 a1 = A1.getInstance(suaConstanteEnumOuInt);

Dá uma pesquisada no padrão de projeto Factory.

dedraks

Minha pergunta ficou imcompleta porque tentei dar um exemplo genérico.
Vou colocar um trecho do meu código REAL aqui pra você entenderem o que quero.

1) Estou fazendo uma aplicação pra Android que pode rodar em dispositivos diferentes.
2) Há um código que é específico para cada dispositivo.
3) Criei uma classe abstrata que define o método em questão.

abstract class DispositivoGenerico {
    abstract void executaCodigo();
}
4) Então criei uma classe pra cada dispositivo que meu programa deve suportar.
class Dispositivo_X111 extends DispositivoGenerico {
    void executaCodigo() {
        // Código específico do dispositivo A
    }
}

class Dispositivo_X222 extends DisposivitoGenerico {
    void executaCodigo() {
        // Codigo específico do dispositivo B
    }
}
No meu programa eu pego uma informação do dispotivo:
String device = android.os.Build.DEVICE; // Obtem o dispositivo que pode ser X111 ou X222
Eu gostaria de poder instanciar isso de forma automática:
//Este código é imaginário
DisposivitoGenerico disposivito = new Dispositivo_****Aqui eu poderia colocar a variável "device" ou algo parecido***();
device.executaCodigo();
No meu código atual, que funciona, estou fazendo conforme abaixo mas acho que não é a melhor forma.
DispositivoGenerico dispositivo;
if (device.equals("X111")) {
    dispositivo = new Dispositivo_X111();
}
else if (device.equals("X222") {
    dispositivo = new Dispositivo_X222();
}
else {
   dispositivo = null;
}
drsmachado

Estude (e muito) reflection.
Tem uns exemplos no guj.
Com reflection é possível instanciar um objeto de uma classe a partir de uma String que a identifica e, invocar métodos, identificar métodos, atributos e uma série de outras possibilidades.

Vai lá camarada.
Ou continua assim…

dedraks

Não sei se é a solução mais correta mas resolvi assim:

Defino a classe abstrata
abstract class DispositivoGenerico {
    abstract String getNome();
    abstract String getFabricante();
}
Defino a classe para o primeiro dispositivo
class Dispositivo_X111 {
    private String _nome = "X111";
    private String _fabricante = "X";

    public String getNome() {
        return _nome;

    public String getFabricante() {
        return _fabricante;
    }
}
Defino a classe para o segundo dispositivo
class Dispositivo_Y123 {
    private String _nome = "X123";
    private String _fabricante = "Y";

    public String getNome() {
        return _nome;

    public String getFabricante() {
        return _fabricante;
    }
}
Defino uma classe Factory pra instanciar o a classe correta (dei uma lida no design pattern Factory e creio que é isso mesmo)
class DFactory_Versao_1 {
    public static DispositivoGenerico getDevice(String modelo) {

		if (model == null) return null;
		if (model.equalsIgnoreCase("X111")) return new Dispositivo_X111();
		if (model.equalsIgnoreCase("ME525")) return new Dispositivo_Y123();

		return null;
	}
}
Pensei em fazer a factory também desse jeito
class DFactory_Versao_2 {
    public static DispositivoGenerico getDevice(String modelo) {

		if (model == null) return null;
		if (model.equalsIgnoreCase(  new Dispositivo_X111().getNome()   )) return new Dispositivo_X111();
		if (model.equalsIgnoreCase(  new Dispositivo_X123().getNome()   )) return new Dispositivo_Y123();

		return null;
	}
}
No meu programa eu executo assim:
DispositivoGenerico dispositivo = DeviceFactory.getDevice(android.os.Build.MODEL);
A variável android.os.Build.MODEL contém o modelo do dispositivo no qual o programa está sendo executado.
Criado 17 de maio de 2011
Ultima resposta 18 de mai. de 2011
Respostas 6
Participantes 4