terça-feira, 13 de janeiro de 2009

Java: Threads concorrentes, swing, observable para conectar objetos a GUI, herança, interface e mais algumas coisas.

Pessoal,

Meu primeiro post no Estação ZN!

Numa manhã sem muito trabalho escrevi um programa em JAVA para ilustrar alguns recursos. Tem threads concorrentes, swing, observable para conectar objetos a GUI, herança, interface e mais algumas coisas.

O programa ilustra a concorrência de dois objetos tentando se conectar para formar uma parceria e se reproduzir em um novo objeto que vai continuar com esse ciclo.

Acredito que esse programa possa ajudar a quem está começando ou quem quer ver um exemplo dos recursos que citei.

Como funciona:

Existe uma classe Elemento que define o objeto principal e que será herdada por Macho e Fêmea. Os Objetos da classe Macho e Fêmea são associados a um objeto da classe Ambiente. A classe Ambiente define o ambiente onde os objetos viverão. A classe Elemento implementa Runnable e no método run executa o código necessário para dar vida aos objetos.

Abaixo um diagrama simplificado dessas classes.


A classe Main é um JFrame que exibe os objetos criados como JButtons. A classe Main possui um método simular que inicia a simulação.

A seguir as principais classes do programa.

Classe: Elemento

package simulador;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

public abstract class Elemento implements Runnable {

private static int contador = 0;
private int id;
private Elemento mae;
private Elemento pai;
private long nascimento;
private long morte;
private int folego = 3 * 1000;
private int idadeMaxima = 2 * 60 * 1000;
private boolean running = true;
private boolean vivo = true;
private boolean ocupado;
protected Ambiente ambiente;
protected Elemento parceiro;
private ArrayList memoria = new ArrayList();
private ArrayList observadoresVida = new ArrayList();
private ArrayList observadoresMorte = new ArrayList();
private ArrayList observadoresParceria = new ArrayList();

public Elemento(Ambiente ambiente) {
id = contador++;
setAmbiente(ambiente);
}

public int getFolego() {
return folego;
}

public void setFolego(int folego) {
this.folego = folego;
}

public int getIdadeMaxima() {
return idadeMaxima;
}

public void setIdadeMaxima(int idadeMaxima) {
this.idadeMaxima = idadeMaxima;
}

public Elemento getMae() {
return mae;
}

public void setMae(Elemento mae) {
this.mae = mae;
}

public Elemento getPai() {
return pai;
}

public void setPai(Elemento pai) {
this.pai = pai;
}

public int getId() {
return id;
}

public ArrayList getMemoria() {
return memoria;
}

protected void memorizar(String s) {
memoria.add(id + ": " + new Date() + ": " + s);
}

public void setAmbiente(Ambiente ambiente) {
this.ambiente = ambiente;
}

public void setRunning(boolean running) {
this.running = running;
}

public boolean isRunning() {
return running && ambiente.isRunnig() && !expirou();
}

public boolean expirou() {
long idade = System.currentTimeMillis() - nascimento;
return idade > idadeMaxima;
}

public long idadeMorte() {
long idade = morte - nascimento;
return idade;
}

public boolean isVivo() {
return vivo;
}

public Elemento getParceiro(){
return parceiro;
}

private synchronized boolean ocupar() {
if (!ocupado) {
ocupado = true;
return true;
} else {
return false;
}
}

private void liberar() {
ocupado = false;
}

private boolean aceitar(Elemento outro) {
if (solteiro() && desejo()) {
String s1 = "Aceitei o convite para ser parceiro do " + outro.id + ".";
notificarEncontrarParceiro(s1);
parceiro = outro;
outro.parceiro = this;
return true;
} else {
String s2 = "N?o aceitei o convite para ser parceiro do " + outro.id + ".";
notificarEncontrarParceiro(s2);
return false;
}
}

private void encontrarParceiro() {
if (ocupar()) {
Random rand = new Random();
int quantidadeDeElementos = candidatos().size();
int aleatorio = rand.nextInt(quantidadeDeElementos);
Elemento outro = candidatos().get(aleatorio);
if (!equals(outro)) {
String s1 = "Escolhi o " + outro.id + " para ser parceiro.";
notificarEncontrarParceiro(s1);
if (!outro.vivo) {
String s2 = "O " + outro.id + " estava morto.";
notificarEncontrarParceiro(s2);
} else if (outro.ocupar()) {
String s3 = "Convidando o " + outro.id + " para ser parceiro.";
notificarEncontrarParceiro(s3);
if (outro.aceitar(this)) {
String s4 = "O " + outro.id + " aceitou ser parceiro.";
notificarEncontrarParceiro(s4);
} else {
String s5 = "O " + outro.id + " n?o aceitou ser parceiro.";
notificarEncontrarParceiro(s5);
}
outro.liberar();
} else {
String s6 = "O " + outro.id + " estava ocupado.";
notificarEncontrarParceiro(s6);
}
}

liberar();
}
}

protected abstract Elemento reproduzir();

protected abstract List candidatos();

protected boolean desejo() {
Random rand = new Random();
int aleatorio = rand.nextInt(2);
if (aleatorio == 1) {
return true;
} else {
return false;
}
}

public boolean equals(Object o) {
Elemento outro = (Elemento) o;
if (outro == this) {
return true;
}
if (outro.id == id) {
return true;
}
return false;
}

public boolean solteiro() {
return parceiro == null;
}

public void run() {
notificarNascimento();
nascimento = System.currentTimeMillis();

while (isRunning()) {
if (solteiro()) {
if (desejo()) {
encontrarParceiro();
}
} else { // Possui um parceiro, pode se reproduzir.

if (desejo() && parceiro.isVivo() && parceiro.desejo()) {
Elemento novo = reproduzir();
if (novo != null) {
try {
new Thread(novo).start();
} catch (OutOfMemoryError e) {
ambiente.setRunning(false);
throw e;
}
}
}
}
if (isRunning()) {
try {
Thread.sleep(folego);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
morte = System.currentTimeMillis();
vivo = false;
notificarMorte();
}

public ArrayList getObservadoresVida() {
return observadoresVida;
}

public ArrayList getObservadoresMorte() {
return observadoresMorte;
}

public ArrayList getObservadoresParceria() {
return observadoresParceria;
}

public void addObservadoresVida(Ouvinte o) {
observadoresVida.add(o);
}

public void addObservadoresMorte(Ouvinte o) {
observadoresMorte.add(o);
}

public void addObservadoresParceria(Ouvinte o) {
observadoresParceria.add(o);
}

private void notificarNascimento() {
memorizar("Nasci.");
for (Ouvinte e : observadoresVida) {
e.atualizar(this, "Nasci.");
}
}

private void notificarMorte() {
memorizar("Morri.");
for (Ouvinte e : observadoresMorte) {
e.atualizar(this, "Morri.");
}
}

private void notificarEncontrarParceiro(String s) {
memorizar(s);
for (Ouvinte e : observadoresParceria) {
e.atualizar(this, s);
}
}

protected void notificarNascimento(Elemento e, String s) {
memorizar(s);
for (OuvinteNascimento o : ambiente.getObservadoresNascimento()) {
o.atualizar(this, e, s);
}
}
}

Classe: Macho
package simulador;

import java.util.List;

public class Macho extends Elemento {

public Macho(Ambiente ambiente){
super(ambiente);
ambiente.getElementosMachos().add(this);
ambiente.getElementos().add(this);
}

protected Elemento reproduzir() {
return null;
}

protected List candidatos() {
return ambiente.getElementosFemeas();
}

}

Classe: Femea
package simulador;

import java.util.List;

public class Femea extends Elemento {

public Femea(Ambiente ambiente) {
super(ambiente);
ambiente.getElementosFemeas().add(this);
ambiente.getElementos().add(this);
}

protected List candidatos() {
return ambiente.getElementosMachos();
}

protected Elemento reproduzir() {
Elemento e;
if (desejo()) {
e = new Femea(ambiente);
notificarNascimento(e, "Pari a femea " + e.getId());
} else {
e = new Macho(ambiente);
notificarNascimento(e, "Pari o macho " + e.getId());
}
e.setMae(this);
e.setPai(parceiro);
return e;
}
}

Classe: Main
package simulador;

public class Main extends javax.swing.JFrame {

public Main() {
initComponents();
}

/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
private void initComponents() {

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Simulador");
getContentPane().setLayout(new java.awt.FlowLayout());

pack();
}//


/**
* @param args the command line arguments
*/
public static void main(String args[]) {
final Main f = new Main();
java.awt.EventQueue.invokeLater(new Runnable() {

public void run() {
f.setVisible(true);
}
});

f.simular();
}
Detalhe detalhe;

public Detalhe detalhe() {
if (detalhe == null) {
detalhe = new Detalhe();
}
return detalhe;
}

public void print(final Elemento e) {
javax.swing.JButton elementoGrafico = new javax.swing.JButton();
elementoGrafico.setText("" + e.getId());
getContentPane().add(elementoGrafico);

elementoGrafico.addMouseListener(new java.awt.event.MouseAdapter() {

@Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
detalhe().setDetalhe(e.getMemoria());
detalhe().setVisible(true);
}
});

pack();
}

public void simular() {
int TEMPO_DE_VIDA = 2 * 60 * 1000;

Ambiente ambiente = new Ambiente();

ambiente.addObservadoresNascimento(new OuvinteNascimento() {

public void atualizar(Elemento mae, Elemento filho, String s) {
print(filho);
}
});

Elemento m = new Macho(ambiente);
print(m);
new Thread(m).start();

Elemento f = new Femea(ambiente);
print(f);
new Thread(f).start();

try {
Thread.sleep(TEMPO_DE_VIDA);
} catch (InterruptedException e) {
e.printStackTrace();
}

ambiente.setRunning(false);

while (ambiente.vivo()) {
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}


System.out.println("Fim.");


}

// Variables declaration - do not modify
// End of variables declaration
}

Não está comentado, mas começando da classe Main ninguém se perde. O programa vem como um projeto Netbeans, mas vai rodar fácil no Eclipse.

Vou continuar melhorando o programa, aceito comentários, sugestões, melhorias e correções!


Obs: A tela de detalhe não se atualiza sozinha.


Abraços, Rodrigo Alencar.

Um comentário:

  1. Oi, encontrei esta pagina por acaso. Estou agora me iniciando no java e este programa excelente fez-me lembrar algo parecido que fiz na universidade, mas em linguagem c. Estou a tentar perceber o codigo do teu programa, mas nao percebo a forma como usas o ciclo "for". Nunca antes tinha visto e ja tive a procurar na net e nao encontro uma explicação para usar o "for" da forma "for ( : )", como em "for (Ouvinte e : observadoresParceria)" Se pudesses me dar uma pequena explicação, agradecia. Obrigado

    ResponderExcluir

 
BlogBlogs.Com.Br