quarta-feira, 15 de abril de 2009

Criando seus proprios eventos no Java

5

A maioria do pessoal que já mexeu com Swing no Java (o que acredito que sejam a maioria do pessoal que já mexeu com java), conheçe o estilo do java tratar eventos, usando classes, assim como nossa querida classe chamada ActionListener, que algumas IDEs como o Netbeans escondem a declaração dessa interface, adotando um estilo mais delphi-style.

E normalmente o pessoal que vem do Delphi, acha estranho declarar um classe e implementar um metodo nela para executar o evento de um botão (Eu também achava isso). Porém os beneficios de adotar esse abordagem, proporciona baixo acoplamento, e seu código pode se tornar mais dinamico e orientado a objetos, não aquele código macarronico que vemos por ai, que muitas pessoas fazem, e eu também faço diversas vezes.

A vantagem de se fazer isso é que o Java não vai sobrescrever o ActionListener que já foi adicionado ao seu botão, ele vai adicionar mais um, ou seja seu botão vai executar duas ações. ou seja, vc pode separar códigos com mais facilidade, e muito mais simples. Mas bah tche como isso?

Vou mostrar como criar seus proprios eventos em Java. Imagine o seguinte problema:

"Como projetar um sistema que modele um telefone e todos os objetos que poderiam estar interessados quando ele toca?"

Rá, ai poderiamos usar o Observer, que expliquei no artigo anterior correto? Sim, poderiamos, mas não é isso que eu quero mostrar :-)

Primeiramente devemos criar o Evento, esse evento será o evento disparado toda a vez que um telefone toca, e vai ficar disponivel para os listeners, é um código realmente simples:


public class TelefoneEvent extends java.util.EventObject {

public TelefoneEvent(Telefone source) {
super(source);
}
}


Simples não, deixemos a herança cuidar disso para nós e o java que cuide de seu EventObject

Agora vamos criar nossa interface Listener, utilizando listener não impedimos a herança, e deixamos a classe livre para criar quantos listeners quiser, ou implementar se for melhor para ela, a implementação do listener


public interface TelefoneListener extends java.util.EventListener {
void telefoneTocou(TelefoneEvent e);
void telefoneAtendido(TelefoneEvent e);
}


Extendendo a interface EventListener, temos um novo evento criado, nosso telefone Listener, possui dois metodos, telefoneTocou e TelefoneAtentido, que devem ser reimplementados, uma solução bacana que o java usa também são os adapters, como KeyAdapter, que possui os metodos de KeyListener implementados sem código ou funcionalidade alguma, vc so sobrescreve os que deseja, os outros são silenciosos (não fazem nada).


public class TelefoneAdapter
implements TelefoneListener {

public void telefoneTocou(TelefoneEvent e) {}
public void telefoneAtendido(TelefoneEvent e) {}
}


Simples não, mas não é só isso, ainda não serve para nada nosso listener.


//imports omitidos
public class Telefone {
private Collection telefoneListeners = new ArrayList();

// método de suporte para testar a solução
public void tocaFone() {
disparaTelefoneTocou();
}

public void atendeFone() {
disparaTelefoneAtendido();
}

public synchronized void addTelefoneListener(TelefoneListener l) {
if(!telefoneListeners.contains(l)) {
telefoneListeners.add(l);
}
}

public synchronized void
removeTelefoneListener(TelefoneListener l) {

telefoneListeners.remove(l);
}

private void disparaTelefoneTocou() {
Collection tl;
synchronized (this) {
tl = (Collection)(((ArrayList)telefoneListeners).clone());
}
TelefoneEvent evento = new TelefoneEvent(this);
for (TelefoneListener t : tl) {
t.telefoneTocou(evento);
}
}

private void disparaTelefoneAtendido() {
Collection tl;
synchronized (this) {
tl = (Collection)(((ArrayList)telefoneListeners).clone());
}
TelefoneEvent evento = new TelefoneEvent(this);
for (TelefoneListener t : tl) {
t.telefoneAtendido(evento);
}
}
}


Essa é uma simples classe como outra qualquer, podem ver que ela possui dois metodos addTelefoneListener e removeTelefoneListener, esses metodos são padrões, em listeners vc não pode utilizar getters e setters, utilizando getter e setter perde-se o encapsulamento. Ele cria antes de disparar os eventos de cada um dos seus listeners, simples e prático.



public class SecretariaEletronica
implements TelefoneListener {

public void telefoneTocou(TelefoneEvent e) {
System.out.println("Secretaria escuta o telefone tocando.");
}

public void telefoneAtendido(TelefoneEvent e) {
System.out.println("Secretaria sabe que o telefone foi atendido.");
}
}
public class Pessoa {
public void escutaTelefone(Telefone t) {
t.addTelefoneListener(
new TelefoneAdapter() {
public void telefoneTocou(TelefoneEvent e) {
System.out.println("Eu pego!");
((Telefone)(e.getSource())).atendeFone();
}
}
);
}
}

Duas classes para melhorar a brincadeira, e vc pode criar mais classes, essas somente ajudam a ilustrar o exemplo

public class ExemploFone {
public static void main(String[] args) {
Telefone fone = new Telefone();
Pessoa fulano = new Pessoa();
SecretariaEletronica se = new SecretariaEletronica();

fone.addTelefoneListener(se);
fulano.escutaTelefone(fone);

fone.tocaFone(); // começa a brincadeira
}
}


a saida é algo assim

Secretaria escuta o telefone tocando.
Eu pego!
Secretaria sabe que o telefone foi atendid


Pode parecer complexo inicialmente, mas isso melhora e agiliza o trabalho, é muito bacana se trabalhar com listeners. Esse exemplo foi encontrado aqui e vc pode utiliza-lo, possui mais detalhes.

Uma leitura bacana, veja aqui no blog do Carlos Brando.





5 comentários:

Anônimo disse...

Tem como dar um exemplo com swing + bd tb colega ?

Anônimo disse...

Excelente... Exemplos bem claros e didáticos. Parabéns!!!

Eduardo Folly disse...

Muito bom o post. Explicação muito boa. Parabéns.

Samuel Cazelli disse...

Ótimo tutorial, valeu!!!

Anônimo disse...

Excelente , ajudou muito.
Valew...

 
Design by ThemeShift | Bloggerized by Lasantha - Free Blogger Templates | Best Web Hosting