Observer
Este artigo não cita fontes confiáveis. (Novembro de 2011) |
O padrão Observer (tambem conhecido como Dependents, Publish-Subscribe) é um padrão de projeto de software (do inglês design pattern), considerado um padrao comportamental, define um dependencia um-para-muitos, onde permite que a modificação do estado de um objeto, notifique seus dependentes, sendo atualizados automaticamente.
Aplicação
Pode ser utilizado quando existe uma abstração de dois aspectos, sendo um dependente do outro, ou também quando um objeto sofre uma mudança obriga mudança em outros objetos, sem saber quantos objetos precisam mudar, ou quando pode ser capaz de notificar outros objetos, sem que os objetos sejam fortemente acoplados.
Estrutura
Estrutura básica do padrão Observer
Participantes
Subject (Sujeito)
- fornece uma interface para acrescentar e remover objetos.
Observer (Observador)
- fornece uma interface com um metodo chamado update() que permite a atualização de todos os objetos dependentes, quando existe mudança no estado de Subject.
ConcreteSubject (Sujeito concreto)
- implementa os métodos da interface Subject, e ainda o um outro método notifyObservers(), utilizado para a atualização dos observadores sempre que o estado for alterado. Alem de poder possuir métodos que permitam definir seu estado.
ConcreteObserver (Observador concreto)
- armazena estados que devem permanecer consistentes com os do Subject, podendo ser qualquer classe que implemente a interface Observer, para manter seu estado consistente com o do subject.
Interação
O ConcreteSubject notifica seus observadores sempre que ocorrer uma mudança, permitindo assim ter uma consistencia dos estados entre ele e seus observadores. Posteriormente ao ser informado, um objeto ConcreteObserver poderá consultar as informações do subject, conciliando suas informações. Pode haver inumeras interfaces do usuário para os mesmos dados, onde o padrão observer permite estabelecer tais relacionamentos. Um subject pode ter diversos observadores dependentes, onde todos são notificados quando o subject sofre uma mudança de estado, sendo apenas o publicador de notificações, enviando essas notificações sem precisar saber quem são os observadores.
Consequências
O padrão Observer permite sujeitos e observadores de foma independente.
Vantagens e Desvantagens
- Assim Tanto observadores quando sujeitos observados podem ser reutilizados e ter sua interface e implementação alteradas sem afetar o sistema.
- Acoplamento forte reduzido com o uso de interfaces e classes abstratas
Permite tembem acrescentar observadores sem modificar o sujeito ou outros observadores, assim como outros beneficios e dificuldades:
- Acoplamento abstrato entre Subject e Observer - O sujeito não conhece a classe concreta de nenhum observador, permitindo que o acoplamento entre o sujeito e os observadores é abstrato e mínimo;
- Suporte para comunicações do tipo broadcast - a notificação é transmitida automaticamente para todos os objetos interessados, sendo que o sujeito não se preocupa com quantos objetos interessados existem;
- Atualizações inesperadas - Critérios de depêndencia que não estão bem-definidos ou mantidos normalmente conduzem a atualização normais que podem ser difíceis de detectar;
Implementação
A seguir demonstra um código fonte em Java, onde representamos uma sala de aula, que possui como sujeito concreto a classe Sinal e Professora, que implementa a inteface Sujeito, e seus observadores temos a classe Aluno e Estagiaria, que implementa a inteface Observer.
Subject
Classe Sujeito
Especifica todos as ações comuns aos sujeitos concretos, que podem adicionar os observadores, remove-los e notifica-los.
// <<interface>> Subject
package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado
// fornece a interface que sera utilizada pelos ConcreteSubject(Professora, Sirene)
public interface Sujeito {
public void addObservador(Observador o);
public void removeObservador(Observador o);
public void notificaObservadores();
}
Observer
Classe Observador
Especifica todos as ações comuns aos obsevadores concretos, que podem ser atualizados.
// <<interface>> Observer
package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado
// fornece a interface que será utilizada pelo ConcreteObserver(Aluno, Estagiaria)
public interface Observador {
public void Update(Sujeito s);
}
ConcreteSubject
Classe Professora
Implementa todas as funções do Subject adicionando e removendo observadores, alem de poder possuir métodos que permitam definir seu estado. Assim ele possui dois observadores que é os observadores concretos Aluno e Estagiaria.
//ConcreteSubject2
package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado
import java.util.ArrayList;
public class Professora implements Sujeito{
private ArrayList<Observador> observadores;
private String comando;
public Professora(){
this.observadores = new ArrayList<Observador>();
}
public void addObservador(Observador o) { // adiciona o observador
this.observadores.add(o);
}
public void removeObservador(Observador o) { // remove o observador
this.observadores.remove(o);
}
public void notificaObservadores() { // notifica os observadores
for(int i = 0; i<this.observadores.size(); i++)
this.observadores.get(i).Update(this);
}
public String getComando() {
return comando;
}
public void setComando(String comando) {
this.comando = comando;
this.notificaObservadores();
}
}
Classe Sirene
Implementa todas as funções do Subject adicionando e removendo observadores, alem de poder possuir métodos que permitam definir seu estado. Assim como o sujeito concreto Professora ele possui dois observadores que é os observadores concretos Aluno e Estagiaria.
//ConcreteSubject1
package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado
import java.util.ArrayList;
public class Sirene implements Sujeito{
private boolean alertaSonoro;
private ArrayList<Observador> observadores;
public Sirene(){
this.observadores = new ArrayList();
}
public void addObservador(Observador o) { // adiciona o observador
this.observadores.add(o);
}
public void removeObservador(Observador o) { // remove o observador
this.observadores.remove(o);
}
public boolean isAlertaSonoro() {
return alertaSonoro;
}
public void setAlertaSonoro(boolean alertaSonoro) {
this.alertaSonoro = alertaSonoro;
this.notificaObservadores();
}
public void notificaObservadores() { // notifica os observadores
for(int i=0; i<this.observadores.size(); i++)
this.observadores.get(i).Update(this);
}
}
ConcreteObserver
Classe Aluno
Implementa todas as funções do Observador que armazena estados que devem permanecer consistentes com os do sujeito concreto para manter seu estado consistente com o do subject.
// ConcreteObserver1
package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado
public class Aluno implements Observador{
public Aluno(){} //Construtor padrão
public void Update(Sujeito s) {
if(s instanceof Sirene)
System.out.println(" Aluno - Hora de entregar a prova!");
else
if(s instanceof Professora)
System.out.println(" Aluno - A professora disse: " + ((Professora) s).getComando());
}
}
Classe Estagiaria
Assim como a classe Aluno, essa classe implementa todas as funções do Observador que armazena estados que devem permanecer consistentes com os do sujeito concreto para manter seu estado consistente com o do subject.
//ConcreteObserver2
package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado
public class Estagiaria implements Observador {
public Estagiaria(){} // construtor padrão vazio da classe Observador
// implementa o método do Observador
public void Update(Sujeito s) {
if(s instanceof Sirene)// se o ConcreteSubject sirene for acionada
System.out.println(" Estagiaria - Tenho que recolher as provas!");
else
if(s instanceof Professora) // se o ConcreteSubject professora for acionada
System.out.println(" Estagiaria - A professora disse: " + ((Professora) s).getComando());
}
}
Classe Main
Tem como função de demostrar um exemplo de execução e troca de comportamento de objetos em tempo de execução pelo padrão Observer.
// classe principal
package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado
// Classe principal do programa
public class Main {
public static void main(String[] args){
// inicializando os sujeito(ConcreteSubject), no caso uma Sirene e uma Professora, mas poderia haver varios sujeitos
Sirene sirene = new Sirene();
Professora professora = new Professora();
// inicialização dos observadores(ConcreteObserver), no caso são quatro observadores, sendo tres alunos e uma estagiaria,
// mas poderia haver varios observadores
Observador aluno1 = new Aluno();
Observador aluno2 = new Aluno();
Observador aluno3 = new Aluno();
Observador estagiaria = new Estagiaria();
// adicionando-os como observadores do ConcreteSubject no caso a Sirene
sirene.addObservador(aluno1);
sirene.addObservador(aluno2);
sirene.addObservador(aluno3);
sirene.addObservador(estagiaria);
// adicionando-os como observadores do ConcreteSubject no caso a Professora
professora.addObservador(aluno1);
professora.addObservador(aluno2);
professora.addObservador(aluno3);
professora.addObservador(estagiaria);
// aplicando uma ação ao Subject Professora
professora.setComando("Vamos aplicar a prova!");
System.out.println("\n 50 min depois\n IIIINNNFFFOOO");
// aplicando uma ação ao Subject Sirene
sirene.setAlertaSonoro(true);
}
}
Estrutura do código fonte
No código existe dois sujeitos concretos que implementa os métodos da interface Sujeito, dois observadores concretos que implementam a interface Observador. Os observadores visualizam as atualizações dos dois sujeitos concretos.
Referências
- ↑ GAMMA, Erich et al. Padrões de Projeto: soluções reutilizáveis de software orientado a objetos. – Porto Alegre: Bookman, 2000.
2. Larman, Craig. Utilizando UML e padrões:uma introdução à análise e ao projeto orientados a objetos e ao desenvolvimento interativo. 3ª. Ed. Porto Alegre:Bookman, 2007.