Padrões de Projeto Observer – Modelagem e Prática
Neste artigo abordaremos a modelagem e prática de um padrão de projeto (Design Patterns) bastante importante do GoF (Gang of Four) que é o Padrão Observer.
A essência desse padrão está na possibilidade de uma classe poder fazer uma 'notificação' a um conjunto de classes associadas de que o Estado (Conjunto de Atributos) dela foi alterado por algum motivo. A definição do padrão observer descrita pelos criadores é a seguinte:
"Definir uma dependência um-para-muitos entre objetos para que quando um objeto mudar de estado, todos os seus dependentes sejam notificados e atualizados automaticamente." [GoF]
Você deve estar pensando "Eu posso fazer essa notificação manualmente ou até mesmo utilizando eventos como actionPerformed para fazer a notificação através de chamas a métodos de cada instância (ufaa)". Porém dessa maneira você estará criado um sistema com alto acoplamento e de difícil manutenabilidade.
Utilizando o padrão Observer conseguimos reduzir o uso do relacionamento bidirecional por meio de interfaces e classes abstratas, separando a abstração para ter um alto nível de coesão e baixo acoplamento.
Para ficar mais intuitivo vamos fazer o uso de exemplos. Imagine um operário de obras que esta trabalhando em uma construção junto com seus 'companheiros'.. O fato de uma sirene tocar implica em uma mudança (mudança de estado), que pode ser um sinal para a hora do almoço, pode ser o final do expediente e etc.
Temos então o seguinte ambiente, o objeto observável (Sirene) e os observadores (Operários). Quando o objeto observável alterar o seu estado, enviará um sinal sonoro (mensagem) alertando os objetos observadores.

Vamos definir as abstrações, chamaremos de Operário a interface do operário e Sirene a interface da sirene como mostrado abaixo:

Perceba que as duas abstrações se relacionam entre si, relacionamento entre interfaces, ou seja, estamos deixando nossa aplicação mais independente separando-as das classes concretas
Na interface Sirene nós especificamos parte do que ela poderá fazer, no caso adicionar ou retirar um observador, da mesma maneira seguiremos com o Operário, sendo que, no mais alto nível de abstração, o mínimo que um observador irá sofrer é o fato de ser notificado (atualizar). Se o operário vai ou não responder ao chamado não cabe a interface.
Com as interfaces em mãos podemos montar nosso diagrama, criaremos duas classes que vão implementar essas interfaces, sendo elas SireneConcreta e OperarioConcreto, conforme vemos abaixo:

Na classe SireneConcreta criaremos todos os outros métodos necessários para o bom funcionamento da sirene e o método notificarObservadores que ira "varrer" o ArrayList que contem uma lista de observadores.
A classe concreta não foge a regra, irá implementar além do método atualizar todos os métodos dos operários.
Tendo toda a estrutura diagramatizada você poderá utilizar o próprio programa de modelagem (se estiver disponível) para gerar o código da nossa estrutura. Eu estou utilizando para esse fim o Enterprise Architect, porém qualquer um com suporte a UML 2.0 (de preferência) poderá ser usado, seja Netbeans, ArgoUML, ou plugins para eclipse..
Implementando nossas interfaces, teremos,
Interface Sirene:
public interface Sirene { public void adicionarObservador( Operario o ); public void removerObservador( Operario o ); }
Interface Operario:
public interface Operario { public void atualizar(Sirene s); }
Com as nossas abstrações prontas, podemos dar inicio a construção das classes concretas, teremos,
Classe SireneConcreta:
import java.util.ArrayList; import java.util.Iterator; public class SireneConcreta implements Sirene { private Boolean alertaSonoro = false; private ArrayList observadores = new ArrayList(); public void alterarAlerta(){ if(alertaSonoro) alertaSonoro = false; else alertaSonoro = true; notificarObservadores(); } public Boolean getAlerta(){ return alertaSonoro; } public void adicionarObservador(Operario o) { observadores.add(o); } public void removerObservador(Operario o) { observadores.remove(o); } private void notificarObservadores(){ Iterator i = observadores.iterator(); while(i.hasNext()){ Operario o = (Operario) i.next(); o.update(this); } } }
Perceba que chamamos o método notificarObservadores exatamente quando o objeto SireneConcreta altera seu estado. Na implementação do método notificarObservadores nos fazemos uma varredura simples e informando a cada instância dele mesmo que o objeto que estava sendo observado mudou seu estado. Repare que estamos trabalhando sempre com as Interfaces ao invés das classes concretas.
Classe OperarioConcreto:
public class OperarioConcreto implements Operario { private SireneConcreta objetoObservado; public OperarioConcreto(SireneConcreta o){ this.objetoObservado = o; objetoObservado.adicionarObservador(this); } public void atualizar(Sirene s) { if(s == objetoObservado){ System.out.println("[INFO] A Sirene mudou seu estado para: " + objetoObservado.getAlerta()); } } }
Com o construtor dessa maneira podemos ao passo de criar o observador e já setar como parâmetro o objeto observado, logo abaixo podemos chamar o método adicionarObservador que passa por referência a sua própria instância!. Interessante, não?
Quando o método atualizar é chamado nós precisamos checar se a sirene que alterou o estado é a mesma que estamos observando.
Com toda estrutura implementada é hora de testar, para tal vamos criar a classe GerenciadorSirene:
public class GerenciadorSirene { public static void main(String[] args) { SireneConcreta sirene = new SireneConcreta(); // Sirete ja começa com valor default false OperarioConcreto obs1 = new OperarioConcreto(sirene); OperarioConcreto obs2 = new OperarioConcreto(sirene); // Já passando a sirene como parametro sirene.alterarAlerta(); // Nesse momento é chamado o método atualizar // das instâncias obs1 e obs2, saída: // [INFO] A Sirene mudou seu estado para: true // [INFO] A Sirene mudou seu estado para: true sirene.alterarAlerta(); //[INFO] A Sirene mudou seu estado para: false //[INFO] A Sirene mudou seu estado para: false // Obs: 2 saídas porque temos 2 observadores } }
É possível dar nomes aos observadores criando um atributo String dentro de OperatorConcreto e passando seu nome para o construtor como segundo parâmetro, para ficar mais fácil diferenciá-los.
Dessa maneira, termino esse artigo sobre o Padrão de Projeto Observer em caso de dúvidas, entre em contato! Bom proveito!









Yeah !!! muito bom!
Mesmo eu não entendendo muita coisa do que li, achei muito bom!! Parabéns aee Rafa!!
muito bom, ta manjando hein rafa…
Essa foi a melhor explicação sobre esse padrão que ja achei, finalmente consegui entender esse padrão, parabéns
Paraabéns, explicação que me ajudou muito com um trabalho de faculdade.Consegui entender muito bem.
[...] você se interessa por Padrão de Projeto veja o artigo Padrão de Projeto Observer [...]
O Padrão de Projeto Observer é ótimo…
Uma Excelente explicação Raquel…
O pessoal só tem q sacar quando o usar o padrão q é o mais complicado!!!
ola rafael, muito bom seu artigo, vc conhece alguam exemplo pratico do mundo real, que utiliza os padroes.. estou tendo dificuldades para encontrar praticidade em coisas reais, geralmente os livros trazem exemplos mais academicos. se souber me avisa.. to querendo aplica-los. obg.
Olá Neto,
Primeiramente obrigado pelo apoio,
Veja, o Padrão Observer é bastante utilizado em bibliotecas de funçṍes e principalmente em quase todos as bibliotecas de GUI (interface gráfica).. assim ele consegue monitorar o evento de cliques ou algo do gênero.
conheça exemplo de aplicações clicando aqui: http://en.wikipedia.org/wiki/Observer_pattern#Implementations
Forte Abraço,
Rafael Capucho.
Muito cara, o padrão foi muito bem explicado.
De facil entendimento XD
Parabens pelo artigo! Muito útil e muito bem explicado!
Muito didático este artigo, exemplos claros e bom texto. Estava a ler um livro bem cansativo sobre o tema e ao encontrar este artigo e ao ler conseguir entender as coisas bem melhor.
Parabéns e obrigado pela postagem.
Olá, Rafael, você indicar onde posso encontrar um exemplo de como usar o padrão Observer com RMI??
Diana Maia,
Olá Diana, veja eu não imagino qual seria o problema na integração entre Observer e RMI ou até mesmo o Corba, a questão é que eles não fazem integração entre si, mas sim uma chamada lançada por um evento.
Se um evento ocorrer no Objeto Observado, você a partir do evento, fazer uma requisição RMI, normalmente. Não consigo entender onde é a dificuldade.
Com atenção,
Rafael Capucho.
Realmente muito bom essa explicação sobre o padrão Observer. Andei ralando muito pra entender o mecanismo disso, mas finalmente entendi!
Muitos sites mostram exemplos complexos demais. Esse aí do alarme foi bem simples e claro.
Obrigado e parabéns!
Olá Rafael Parabéns,
Apenas uma correção, creio que no método notificarObservadores() da Classe SireneConcreta, quando se dar o.update(this), talvez o certo seria o.atualizar(this). ou não?
A correção é simples, mas sem ela, esse erro poderá gerar duvidas em muitos iniciante.
Parabéns Novamente, muito Boa a explicação.
[]’s