Ir para o conteúdo
bloodspader

Que pattern utilizar?

Mensagens Recomendadas

bloodspader

Boas, estou com uma duvida em relação à utilização de uma determinada pattern para conseguir eliminar este case na classe MenuPrincipal do meu programa

Penso que talvez fosse melhor utilizar a pattern visitor em conjunto com a prototype, mas de facto não sei como fazê-lo, pois já fiz a alteração às classes que pretendo alterar, mas não consigo utilizá-los na classe MenuPrincipal. Por exemplo , na FabricaVeiculos são criados todos os objectos, e utilizando o clone apenas me retorna uma cópia desse objecto criado, ou seja, não consigo alterar o seu comportamento, pois a DroneConfigDialog e que trata disso. Alguém me pode ajudar?

MenuPrincipal.java

  
.
.
.
.

                                switch( tipoDrone ){
			case DroneConfigDialog.DRONE_PESADO:
				d = FabricaVeiculos.criaDronePesado( hangar, destino, tipoAtaqueDrone );
				break;
			case DroneConfigDialog.DRONE_LEVE:
				d = FabricaVeiculos.criaDroneLeve( hangar, destino, tipoAtaqueDrone );
				break;
			case DroneConfigDialog.DRONE_MEDIO:
				d = FabricaVeiculos.criaDroneMedio( hangar, destino, tipoAtaqueDrone );
				break;
			}
.
.
.
.

   

FabricaVeiculos.java

       
public static Drone criaDroneMedio( Point2D.Double hangar, Point2D.Double destino, int modoAtaque){

                ImageLoader loader = ImageLoader.getImagemCarregada();	
	Image img = loader.getImage("data/inimigos/drone.gif");

	// definição das características do drone
	ComponenteSimples sprite = new ComponenteSimples( img ); 
	Drone drone = new Drone( sprite );
	drone.setHangar( hangar );
	drone.setPosicao( hangar );
	drone.setDestino( destino );
	drone.setSpeed( 2 );
	drone.setNProjecteis( 6 );
	drone.setPotencia( 2 );
	drone.setTempoActivo( 200 );
	drone.setModoAtaque( modoAtaque );
	return drone;
}

public static Drone criaDroneLeve( Point2D.Double hangar, Point2D.Double destino, int modoAtaque){

	ImageLoader loader = ImageLoader.getImagemCarregada();
	Image img = loader.getImage("data/inimigos/drone.gif");

	// definição das características do drone
	ComponenteSimples sprite = new ComponenteSimples( img ); 
	Drone drone = new Drone( sprite );
	drone.setHangar( hangar );
	drone.setPosicao( hangar );		
	drone.setDestino( destino );
	drone.setSpeed( 4 );
	drone.setNProjecteis( 6 );
	drone.setPotencia( 1 );
	drone.setTempoActivo( 300 );
	drone.setModoAtaque( modoAtaque );
	return drone;
}

  

DroneConfigDialog.java

public class DroneConfigDialog extends JDialog implements VisitanteDrones {
// constantes para os tipos de drones
public static final int DRONE_PESADO = 0;
public static final int DRONE_MEDIO  = 1;
public static final int DRONE_LEVE   = 2;

private static final long serialVersionUID = 1L;

private JPanel jContentPane = null;

private JLabel tipoLbl = null;

private JComboBox tipoCB = null;

private JLabel tipoAtaqueLbl = null;

private JComboBox tipoAtaqueCB = null;

private JButton okBt = null;

// estes dois arrays deverão estar pela mesma ordem
// para garantir que os tipos correspondem aos textos
private String []dronesStr = { "Pesado", "Médio", "Leve" };
private int []drones = {DRONE_PESADO, DRONE_MEDIO, DRONE_LEVE };

private String []ataquesStr = { "Mais Forte", "Mais Fraco", "Mais rápido", "Mais perto", "Ataca de frente" };
private int []ataques = {Drone.MAIS_FORTE, Drone.MAIS_FRACO, Drone.MAIS_RAPIDO, 3, 4};

private List <String> modosAtaque = new ArrayList<String>();


public List <String> getModosAtaque (){
	return modosAtaque;
}

/**
 * @param owner
 */
public DroneConfigDialog(Frame owner) {
	super(owner);
	this.setUndecorated( true ); // tirar o título e o botão de desligar
	initialize();
	this.setLocationRelativeTo( owner );
}

/**
 * devolve o tipo de drone a usar
 * @return o tipo de drone a usar (pesado, médio, leve)
 */
public int getTipoDrone() {		
	// como os arrays estão pela mesma ordem pode-se usar o índice escolhido para 
	// determinar qual o tipo de drone a usar
	return drones[ tipoCB.getSelectedIndex() ];
}

/**
 * devolve o tipo de ataque do drone a usar
 * @return o tipo de ataque do drone a usar (mais fraco, mais leve, mais rápido)
 */
public int getTipoAtaque() {
	// como os arrays estão pela mesma ordem pode-se usar o índice escolhido para 
	// determinar qual o tipo de ataque a usar
	return ataques[ tipoAtaqueCB.getSelectedIndex() ];
}


/**
 * This method initializes this
 * 
 * @return void
 */
private void initialize() {
	this.setSize(416, 100);
	this.setContentPane(getJContentPane());
}

/**
 * This method initializes jContentPane
 * 
 * @return javax.swing.JPanel
 */
private JPanel getJContentPane() {
	if (jContentPane == null) {
		tipoAtaqueLbl = new JLabel();
		tipoAtaqueLbl.setBounds(new Rectangle(221, 16, 170, 12));
		tipoAtaqueLbl.setHorizontalAlignment(SwingConstants.CENTER);
		tipoAtaqueLbl.setText("Aquisição de alvo");
		tipoLbl = new JLabel();
		tipoLbl.setBounds(new Rectangle(17, 11, 147, 16));
		tipoLbl.setHorizontalAlignment(SwingConstants.CENTER);
		tipoLbl.setText("Tipo de drone");
		jContentPane = new JPanel();
		jContentPane.setLayout(null);
		jContentPane.add(tipoLbl, null);
		jContentPane.add(getTipoCB(), null);
		jContentPane.add(tipoAtaqueLbl, null);
		jContentPane.add(getTipoAtaqueCB(), null);
		jContentPane.add(getOkBt(), null);
	}
	return jContentPane;
}

/**
 * This method initializes tipoCB	
 * 	
 * @return javax.swing.JComboBox	
 */
private JComboBox getTipoCB() {
	if (tipoCB == null) {			
		tipoCB = new JComboBox( dronesStr );
		tipoCB.setBounds(new Rectangle(15, 31, 159, 25));
	}
	return tipoCB;
}

/**
 * This method initializes tipoAtaqueCB	
 * 	
 * @return javax.swing.JComboBox	
 */
private JComboBox getTipoAtaqueCB() {
	if (tipoAtaqueCB == null) {
		tipoAtaqueCB = new JComboBox( ataquesStr );
		tipoAtaqueCB.setBounds(new Rectangle(221, 34, 167, 26));
	}
	return tipoAtaqueCB;
}

/**
 * This method initializes okBt	
 * 	
 * @return javax.swing.JButton	
 */
private JButton getOkBt() {
	if (okBt == null) {
		okBt = new JButton();
		okBt.setBounds(new Rectangle(143, 61, 96, 27));
		okBt.setText("Ok");
		okBt.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent e) {
				DroneConfigDialog.this.setVisible( false );
			}
		});
	}
	return okBt;
}

public void visitaDrone(Drone d) {
	d.aceita(this);	
}

}


---

Edit (Baderous): GeSHi adicionado

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
morsa

Não sei se encaixa na perfeição mas já pensaste em usar um Factory Pattern? Pelo menos é o padrão que me parece do que vi. Não sou PRO em Java mas tu pretendes criar Drones de tipos diferentes mas são todos eles Drones. Portanto, é como teres pizzas: tens vários "tipos de pizza" mas não deixam de ser pizzas ;)

http://www.devdaily.com/java/java-factory-pattern-example

http://www.oodesign.com/factory-pattern.html

Espero que ajude.

1abraço

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
joseerodrigues

deja vu ....

http://www.portugal-a-programar.pt/index.php?showtopic=49240

vê lá se é o mesmo projecto, e se serve de ajuda...

Ainda assim, são poucos os elementos que variam na criação de um drone por tipo, poderias perfeitamente guardar as infos de config para cada tipo de drone num ficheiro e usar esses dados para o construir. Eliminavas esse switch e passavas a ter apenas um Factory.createDroneByType(droneType).

Como alternativa mais simples ainda (menos elegante na minha opiniao), se só pretendes mesmo eliminar esse switch, podes perfeitamente ter um hashMap com os tipos de drone e o respectivo nome do método, e chamas esse método via reflection (funciona pois cada um dos teus criaDrone* tem o mm numero e tipo de parametros).

Se pretenderes tentar esta abordagem, este link talvez te seja util : http://wikijava.org/wiki/Class_and_static_Method_Reflection_example

Cumprimentos,

José Rodrigues

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
bloodspader

De facto o projeto é semelhante... ;) pois é um trabalho escolar.  A Abstract Factory seria mais fácil de implementar, sim...mas no entanto não a posso utilizar, por isso tenho que ir por outro caminho. Dai a minha tentativa de implementar a pattern visitor, que visitasse a classe Drone, a DroneConfigDialog, para alterar o comportamento na hora de alterar os drones e caso se adicionassem novos tipos, não se alterasse a classe MenuPrincipal.

Cumprimentos.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
joseerodrigues

Talvez estejamos a falar de coisas diferentes...

Eu pelo menos, não sugeri nenhuma abstract factory (até porque tens sempre uma dependencia da implementação, neste caso, ao decidir qual factory concreta escolher).

Sugeri apenas que fosse adicionado um método á factory que já tens, que devolvesse um drone apenas pelo tipo dele, sendo que a info de config do drone(speed, nprojecteis, potencia, tempoactivo) estaria armazenada algures, pois é a unica coisa que vejo a variar entre tipos de drones.

O problema que vejo com o Visitor para o que pretendes, que é eliminar um switch, é que a ideia do visitor é definir nova funcionalidade quando o tipo (class type) é diferente, que não acontece aqui. Neste caso, pretendes apenas generalizar a forma de criação de drones, não vais agir sobre eles...

Cumprimentos,

José Rodrigues

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
op_h2tuga

Talvez estejamos a falar de coisas diferentes...

Eu pelo menos, não sugeri nenhuma abstract factory (até porque tens sempre uma dependencia da implementação, neste caso, ao decidir qual factory concreta escolher).

Sugeri apenas que fosse adicionado um método á factory que já tens, que devolvesse um drone apenas pelo tipo dele, sendo que a info de config do drone(speed, nprojecteis, potencia, tempoactivo) estaria armazenada algures, pois é a unica coisa que vejo a variar entre tipos de drones.

O problema que vejo com o Visitor para o que pretendes, que é eliminar um switch, é que a ideia do visitor é definir nova funcionalidade quando o tipo (class type) é diferente, que não acontece aqui. Neste caso, pretendes apenas generalizar a forma de criação de drones, não vais agir sobre eles...

Cumprimentos,

José Rodrigues

Viva,

O que sugerias era que variáveis como speed, nProjecteis etc fossem locais? A minha grande questão é, eu selecciono o tipo de drone na combobox , e depois carrego no botão "OK" e a seguir a esse passo têm que começar a sair drones desse tipo que escolhi, eu consigo fazer isso, mas o problema é que estou a utilizar if's para diferenciá-los e eu estou "proibido" de usar if's. Devido a a já não se estar no inicio desta linguagem e ter que se aplicar os conceitos que se vão adquirindo.

Cumprimentos

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
joseerodrigues

Não, o que sugiro é que essas variaveis, que são as unicas que diferenciam o tipo de drones e têm sempre valores concretos, estivessem agrupadas por tipo de drone, sendo que para criar um drone de determinado tipo, iria ser obtida a "config" para o drone, a aplicada no novo objecto, OU, usando sim um prototype, clonar o tipo de drone pretendido e depois atribuir as outras variaveis (hangar, destino, modoataque, etc).

Todo este processo estaria dentro da

FabricaVeiculos

num novo método "createDroneByType(droneType)". O switch do menuPrincipal seria apenas substituido por uma chamada a este método.

A forma como irias obter os dados para construir um novo drone é indiferente (private static HashMap<Integer, ConfigData>, ficheiro xml, properties, ...).

Abaixo segue uma demonstração do que quero dizer, usando objectos de "config" em vez de prototypes (se consegues garantir q são apenas as variaveis de estado do drone que identificam o seu tipo. Se tiveres necessidade de comportamentos diferentes para alem disso, então subclasses de drone por tipo, e sim, prototypes.)

ex:

//FabricaVeiculos

public static Drone criaDrone( Point2D.Double hangar, Point2D.Double destino, int modoAtaque, int tipoDrone){
    Drone retDrone = createProto(tipoDrone);

    retDrone.setHangar( hangar );
    retDrone.setPosicao( hangar );
    retDrone.setDestino( destino );
    retDrone.setModoAtaque( modoAtaque );

    return retDrone;
}

private static Drone createProto(int tipoDrone){

                //private static ConfigData getConfig(int tipoDrone);

                ConfigData conf = getConfig(tipoDrone); // lê xml, properties, array, map, voodoo, etc..

                ImageLoader loader = ImageLoader.getImagemCarregada();  
                Image img = loader.getImage("data/inimigos/drone.gif");
                
                // definição das características do drone
                ComponenteSimples sprite = new ComponenteSimples( img ); 
                Drone drone = new Drone( sprite );
                
                drone.setSpeed( conf.getSpeed() );
                drone.setNProjecteis( conf.getNProjecteis() );
                drone.setPotencia( conf.getPotencia() );
                drone.setTempoActivo( conf.getTempoActivo() );
                
                return drone;
}

Espero que assim me tenha feito entender de forma mais clara ;)

Cumprimentos,

José Rodrigues

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.