Monday, May 4, 2009Observer em Java
Salve galera.
Hoje iremos abordar um padrão de projeto designado Observer.
Observer é um padrão de projeto que se caracteriza em uma associação 1 x N entre objetos. Em que quando um dos objetos muda de estado ou característica, todos os objetos relacionados sejam notificados.
Um objeto do lado 1 da relação deve permitir acesso a seus elementos sem que sua estrutura interna seja exposta.
Como podemos implementar de uma forma abstrata e sem acoplamento a relação, sendo que qualquer alteração no objeto todos os seus relacionados sejam notificados e que eles não se conhecem em tempo de compilação?
Devemos ter em mente os seguintes requisitos:
- Os objetos relacionados devem conhecer o objeto de interesse, mas não devem estar
- O objeto de interesse ( lado 1 da relação), deve notificar os objetos relacionados e interessados sobre ocorrência modificações.
Deve ser implementado de uma forma que os objetos não se conheçam em tempo de compilação, possibilitando acoplamento em tempo de execução e desfazê-lo a qualquer momento.
Aplicabilidade do padrão é quando necessitamos encapsular dois objetos por uma interface em que eles não se conheçam, sendo assim eles ficam completamente desacoplados, possibilitando o reuso separadamente de cada objeto.
Bem, vamos ao que interessa.
Imagine a seguinte situação de envio de email.
- O remetente deseja saber quando o email chegou a caixa postal do destinatário e também saber quando o email foi lido.
- O destinatário deseja saber quando chegou um novo email na caixa postal.
Como podemos implementar isso sem que destinatário e remetente estejam acoplados?
Primeiramente criaremos uma classe EmailEvent que representará os eventos ocorridos sobre um email.
package br.com.ronaldorigoni.observer;
/**
* Classe EmailEvent, representa todo e qualquer evento ocorrido com um email.
* Classe herda de java.util.EventObject para podermos manipular o método
* getSource(), que nos devolve o email que ocorreu o evento.
*
* @author ronaldorigoni.com.br
*/
public class EmailEvent extends java.util.EventObject {
public EmailEvent(Object source) {
super(source);
}
}
Em seguida deveremos criar uma interface EmailListener que será implementada pelo Remetente e Destinatário, que será através dela que eles serão notificados.
package br.com.ronaldorigoni.observer;
/**
* Interface de Listeners para email.
* @author ronaldorigoni.com.br
*
*/
public interface EmailListener {
public void emailRecebido(EmailEvent emailEvent);
public void emailLido(EmailEvent emailEvent);
}
Agora criaremos a classe Email, conforme abaixo.
package br.com.ronaldorigoni.observer;
import java.util.ArrayList;
import java.util.Collection;
/**
* Representa um email.
*
* @author ronaldorigoni.com.br
*
*/
public class Email {
/**
* Lista de objetos interessados nos eventos ocorridos com um email.
*/
private Collection<EmailListener> emailListeners =
new ArrayList<EmailListener>();
/**
* Envia um email.
*
* @param email
*/
public void enviar() {
disparaEmailRecebido();
disparaEmailLido();
}
/**
* Dispara um evento quando este email for recebido.
*/
public void emailRecebido() {
this.disparaEmailRecebido();
}
/**
* Dispara um evento quando este email for lido.
*/
public void emailLido() {
this.disparaEmailLido();
}
/**
* Método sincronizado para impedir que seja adicionado o mesmo listener
* mais de uma vez.
*
* @param emailListener
* - o Listener
*/
public synchronized void addEmailListener(EmailListener emailListener) {
this.emailListeners.add(emailListener);
}
/**
* Remove um listener.
*
* @param emailListener
* O listener.
*/
public synchronized void removeEmailListener(EmailListener emailListener) {
this.emailListeners.remove(emailListener);
}
/**
* Notifica todos os listeners que um email foi lido.
*/
private void disparaEmailLido() {
// criando um evento do próprio email
EmailEvent event = new EmailEvent(this);
// iterando sobre todos os listeners
// para notificar evento de email lido.
for (EmailListener listener : emailListeners) {
listener.emailLido(event);
}
}
/**
* Notifica todos os listeners que um email foi recebido.
*/
private void disparaEmailRecebido() {
// criando um evento do próprio email
EmailEvent event = new EmailEvent(this);
// iterando sobre todos os listeners
// para notificar evento de email recebido.
for (EmailListener listener : emailListeners) {
listener.emailRecebido(event);
}
}
}
Em seguida criaremos as classes Remetente e Destinatario, que deverão implementar a interface EmailListeners pois se tratam de interessados nos eventos ocorridos sobre os emails.
package br.com.ronaldorigoni.observer;
/**
* Representa um destinatário para um email.
* @author ronaldorigoni.com.br
*
*/
public class Destinatario implements EmailListener {
@Override
public void emailLido(EmailEvent emailEvent) {
Email email = (Email) emailEvent.getSource();
System.out.println("DESTINATÁRIO: Você acabou de ler o email:" + email + ".");
}
@Override
public void emailRecebido(EmailEvent emailEvent) {
Email email = (Email) emailEvent.getSource();
System.out.println("DESTINATÁRIO: Você acabou de receber um novo email:"+email);
}
}
E a classe Remetente.
package br.com.ronaldorigoni.observer;
/**
* Representa um
* @author ronaldorigoni.com.br
*
*/
public class Remetente implements EmailListener {
@Override
public void emailLido(EmailEvent emailEvent) {
Email email = (Email) emailEvent.getSource();
System.out.println("REMETENTE: O email " + email + " acaba de ser lido.");
}
@Override
public void emailRecebido(EmailEvent emailEvent) {
Email email = (Email) emailEvent.getSource();
System.out.println("REMETENTE: O email " + email
+ " acaba de ser recebido pelo destinatário.");
}
}
Agora criaremos a classe CaixaPostal que é onde a nossa brincadeira acontece.
package br.com.ronaldorigoni.observer;
/**
* Representa uma caixa postal para teste sobre emails.
* @author ronaldorigoni.com.br
*
*/
public class CaixaPostal {
public static void main(String[] args) {
// criando dois emails
Email email1 = new Email();
Email email2 = new Email();
// criando destinatário e remetente
Destinatario destinatario = new Destinatario();
Remetente remetente = new Remetente();
// Adicionaodo os listeners aos emails
email1.addEmailListener(destinatario);
email1.addEmailListener(remetente);
email2.addEmailListener(destinatario);
email2.addEmailListener(remetente);
/**
* Aqui é onde tudo acontece, brinque com os codigos abaixo,
* comente e descomente as linhas.
*/
email1.enviar();
email2.emailRecebido();
//email2.emailLido();
}
}
Execute o arquivo CaixaPostal.java e veja que quando um email é enviado tanto o remetente quando o destinatário são notificados nenhum conhece a implementação do outro.
Segue aqui o aqui para download do projeto
Bom por hoje fico por aqui, qualquer duvidas ou sugestões segue meu email ronaldo@ronaldorigoni.com.br
Até um próximo post.

Português
Italiano
English