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.