Padrão Observer - Dei-Isep

Propaganda
Padrão Observer
No padrão Observer temos dois objectos:
 um, designado Sujeito (Subject) que possui uma dada informação que pode
variar ao longo da execução do programa,
 e outro, designado Observador (Observer) que está interessado em ser notificado
sempre que essa informação varie.
O padrão Observer diz-nos como estruturar as classes e objectos de modo a que o
Sujeito e o Observador tenham baixo acoplamento, minimizando a interdependência
entre estes dois objetos.
Os objectos Observadores registam-se (subscrevem ) no objecto Sujeito para receberem
actualizações quando os dados do objecto Sujeito mudarem.
Quando os dados no objecto Sujeito mudam, os observadores são notificados.
O padrão Observer define uma relação de dependência entre o sujeito e os observadores,
de um-para-muitos, tal que quando um objecto (sujeito) muda de estado, todos os seus
dependentes (observadores) são notificados e actualizados automaticamente. A relação é
entre um sujeito e muitos observadores.
interface IObservavel:
public interface IObservavel {
void registarObservador(IObservador o);
void removerObservador(IObservador o);
void notificarObservadores();
//
//
//
//
regista um IObservador
remove um IObservador
notifica todos os Observadores
quando o estado do Sujeito muda
}
classe Sujeito:
import java.util.ArrayList;
public class Sujeito implements IObservavel {
private ArrayList observadores = new ArrayList();
private int temperatura;
//dados que podem variar;
// regista um IObservador
public void registarObservador(IObservador o) {
observadores.add(o);
}
// remove um IObservador
public void removerObservador(IObservador o) {
int i = observadores.indexOf(o);
if (i>=0) observadores.remove(i);
}
// notifica todos os Observadores quando o estado do Sujeito muda
public void notificarObservadores() {
for (int i = 0; i < observadores.size(); i++) {
IObservador observador = (IObservador) observadores.get(i);
observador.actualizar(temperatura);
}
}
// simula ocorrencia de variacoes dos dados
public void iniciarVariacaoTemperatura() {
while (true) {
try { Thread.sleep(5000); } catch (InterruptedException e) {}
int variacao = 1 + (int) (5 * Math.random());
int sinalVariacao = (Math.random() < 0.5) ? -1 : 1;
variacao = sinalVariacao * variacao;
mudaTemperatura(variacao);
}
}
private void mudaTemperatura(int variacao) {
this.temperatura += variacao;
notificarObservadores();
}
}
interface IObservador:
public interface IObservador {
void actualizar(int temperatura);
}
classe Observador1:
public class Observador1 implements IObservador {
private int temperatura;
public void actualizar(int temperatura) {
this.temperatura = temperatura;
display();
}
public void display() {
System.out.println("Observador1: temperatuta actual= " + temperatura);
}
}
classe Observador2:
public class Observador2 implements IObservador {
private int temperatura;
public void actualizar(int temperatura) {
this.temperatura = temperatura;
display();
}
public void display() {
System.out.println("Observador2: temperatuta actual= " + temperatura);
}
}
classe Main:
public class Main {
public static void main(String[] args) {
Sujeito sujeito = new Sujeito();
IObservavel suj = sujeito;
IObservador obs1 = new Observador1();
IObservador obs2 = new Observador2();
suj.registarObservador(obs1);
suj.registarObservador(obs2);
sujeito.iniciaVariacaoTemperatura();
}
}
A classe do objeto Sujeito não conhece os objetos Observadores concretos que notifica.
Apenas sabe que implementam a interface IObservador, o que lhe permite conhecer
uma interface comum a todos os observadores para lhes comunicar alterações no seu
estado.
O objeto sujeito apenas depende de uma lista de objetos que implementam a interface
IObservador. Em qualquer altura (mesmo em runtime) podemos adicionar ou remover
observadores.
Não é necessário modificar a classe do objeto Sujeito para adicionar ou remover
observadores. A classe do objeto Sujeito implementa a interface IObservavel, o que
garante que o objecto Sujeito pode registar observadores, remover observadores e
notificar observadores. Para registar ou remover um observador num objeto Sujeito usase a interface IObservador.
Deste modo um objeto Sujeito, sempre que o seu estado muda, notifica um objeto
observador, mas apenas existe um fraco acoplamento entre estes dois objetos.
As classes dos objetos Observadores também não conhecem o objeto Sujeito.
No padrão Observer os objectos sujeito e observadores estão fracamente acoplados, isto
é, podem interatuar mas têm pouco conhecimento uns dos outros.
Mudanças quer na classe Sujeito quer numa classe Observador não afetarão a outra,
desde que estas classes implementem as respectivas interfaces. O baixo acoplamento
entre estas duas classes permite-nos fazer mudanças em qualquer uma, desde que os
objectos Sujeito e Observador cumpram o contrato especificado nas respetivas
interfaces.
Padrão Observer da API do Java
A linguagem Java tem suporte para o padrão Observer incorporado no package java.util:
classe Observable (semelhante ao interface IObservavel), e interface Observer
(semelhante ao interface IObservador).
Observable é uma classe e não uma interface, portanto a classe Sujeito deve estender a
superclasse java.util.Observable.
A classe Observable da API do Java já implementa todos os métodos necessários pra
fornecer o comportamento observador/observável. A classe Sujeito a criar, subclasse de
Observable, só necessita de aceder ao estado interno do objecto Observável, para
sinalizar que o estado mudou (setChanged) e enviar notificação para todos os
observadores registados (notifyObservers).
public class java.util.Observable {
// adiciona um observador ao conjunto dos observadores deste objeto
public synchronized void addObserver(Observer o)
// remove um observador ao conjunto dos observadores deste objeto
public synchronized void deleteObserver(Observer o)
// coloca uma flag interna que indica que o estado deste objeto Observable mudou
protected synchronized void setChanged()
// coloca uma flag interna que indica que o estado deste objeto Observable não mudou
protected synchronized void clearChanged()
// verifica a flag interna para ver se o estado deste Observable mudou e notifica todos os
// observadores; o argumento arg indica o que mudou
public void notifyObservers(Object arg)
// verifica a flag interna e notifica todos os observadores se o objeto mudou
public void notifyObservers()
. . .
}
O método notifyObservers(Object arg) verifica se o estado deste Observable
mudou, como indicado pelo método hasChanged, notifica todos os observadores e em
seguida invoca o método clearChanged para colocar uma flag interna para indicar que
este objecto não mudou. Cada objecto observador tem o seu método update com dois
argumentos: este objeto sujeito e o argumento arg. O argumento arg pode ser usado
para indicar que atributo do sujeito que mudou.
O método notifyObservers() é semelhante ao de cima mas não envia o argumento
arg. Neste caso o observador não recebe indicação sobre qual o atributo do sujeito que
mudou.
A interface Observer declara o seguinte método:
update(Observable obs, Object arg)
Uma classe implementa a interface Observer quando quer ser informada de mudanças
em objetos Observable. O método notifyObservers da classe Observable notifica
todos os objectos Observer registados invocando para cada um o método
update(Observable obs, Object arg). O 1.º argumento do método update serve
para o observer poder interrogar o objecto observable para determinar o seu novo
estado.
classe Sujeito:
import java.util.Observable;
public class Sujeito extends Observable {
private int temperatura = 20;
//dados do sujeito que podem variar
// simula ocorrencia de variacoes da temperatura
public void iniciaVariacaoTemperatura() {
while (true) {
try { Thread.sleep(5000); } catch (InterruptedException e) {}
int variacao = 1 + (int) (5 * Math.random());
int sinalVariacao = (Math.random() < 0.5) ? -1 : 1;
variacao = sinalVariacao * variacao;
mudaTemperatura(variacao);
}
}
private void mudaTemperatura(int variacao) {
this.temperatura += variacao;
setChanged();
notifyObservers(temperatura);
}
}
classe Observador1:
import java.util.Observer;
import java.util.Observable;
public class Observador1 implements Observer {
private int temperatura;
public void update(Observable sujeito, Object temperatura) {
this.temperatura = (Integer)temperatura;
display();
}
public void display() {
System.out.println("Observador1: temperatuta actual= " + temperatura);
}
}
classe Observador2:
import java.util.Observer;
import java.util.Observable;
public class Observador2 implements Observer {
private int temperatura;
public void update(Observable sujeito, Object temperatura) {
this.temperatura = (Integer)temperatura;
display();
}
public void display() {
System.out.println("Observador2: temperatuta actual= " + temperatura);
}
}
classe Main:
public class Main {
public static void main(String[] args) {
Sujeito sujeito = new Sujeito();
Observable suj = sujeito;
Observer obs1 = new Observador1();
Observer obs2 = new Observador2();
suj.addObserver(obs1);
suj.addObserver(obs2);
sujeito.iniciaVariacaoTemperatura();
}
}
Download