Vés al contingut

Patró observador

De la Viquipèdia, l'enciclopèdia lliure
Diagrama UML del Patró Observador

El patró observador (observer, en anglès, i de vegades conegut com a publica/subscriu) és un patró de disseny utilitzat en programació d'ordinadors per a observar l'estat d'un objecte en un programa. Està relacionat amb el principi d'invocació implícita.

Aquest patró es fa servir principalment per a implementar sistemes de tractament d'esdeveniments distribuïts. En alguns llenguatges de programació, els problemes tractats per aquest patró, són tractats a la sintaxi de tractament d'esdeveniments nativa. Aquesta és una funcionalitat molt interessant en termes de desenvolupament d'aplicacions en temps real.

Sumari

[modifica]

L'essència d'aquest patró és que un o més objectes (anomenats observadors o escoltadors) són registrats (o es registren ells mateixos) per a observar un esdeveniment que pot ser llençat per l'objecte observat (el subjecte). L'objecte que pot llençar un esdeveniments generalment manté una col·lecció d'observadors.

Classes participants

[modifica]

Els participants del patró es mostren a continuació. Les funcions dels membres es llisten amb punts.

Subjecte

[modifica]

Aquesta classe abstracta proporciona una interfície per a afegir i treure observadors. La classe subject també manté una llista privada d'observadors. Conté aquestes funcions (mètodes):

  • Afegir - Afegeix un nou observador a la llista d'observadors que observen el subjecte.
  • Treure - Eliminar un observador existent de la llista d'observadors que observen el subjecte.
  • Notificar - Notifica a cada observador cridant a la funció notify() a l'observador, quan ocorre un canvi.

SubjecteConcret

[modifica]

Aquesta classe proporciona l'estat d'interès als observadors. També envia una notificació a tots els observadors, cridant a la funció Notify a la seva superclasse (p. ex., a la classe Subjecte). Conté aquesta funció:

  • ObtéEstat - Retorna l'estat del subjecte.

Observador

[modifica]

Aquesta classe defineix una interfície d'actualització per a tots els observadors, per a rebre notificacions d'actualització des del subjecte. La classe observador és utilitzada com a classe abstracta per a implementar observadors concrets. Conté aquesta funció:

  • Notificar - Una funció abstracta, perquè sigui sobrecarregada per observadors concrets.

ObservadorConcret

[modifica]

Aquesta classe manté una referència amb l'ObjecteConcret, per a rebre l'estat del subjecte quan es rep una notificació. Conté aquesta funció:

  • Notificar - Aquesta és la funció sobrecarregada a la classe concreta. Quan aquesta funció és cridada pel subjecte, l'ObservadorConcret crida a la funció ObtéEstat del subjecte per a obtenir la informació que té sobre l'estat de l'objecte.

Quan l'esdeveniment és llançat cada observador rep una segona crida. Aquesta pot ser o bé una funció virtual de la classe observador (anomenada notify() al diagrama) o bé un punter a una funció (més generalment, un objecte funció o "functor") passat com a argument al mètode d'enregistrament d'escoltadors. A la funció de notificació també se li poden passar alguns paràmetres (generalment, informació sobre l'esdeveniment que ha ocorregut) que poden ser utilitzats per l'observador.

Cada observador concret implementa la funció de notificació i com a conseqüència, defineix el seu propi comportament quan la notificació arriba.

Usos típics

[modifica]

Els usos típics del patró observador:

El patró observador també és associat molt sovint amb el paradigma model-vista-controlador (MVC). A MVC, el patró observador es fa servir per a crear una mena d'unió entre el model i la vista. Típicament, una modificació en el model llença la notificació dels observadors del model, que són, realment, les vistes.

Un exemple es Java Swing, en què s'espera que el model notifiqui els canvis a les vistes mitjançant la infraestructura PropertyChangeNotification. Les classes del model són Java beans que es comporten com el subjecte, descrit abans. Les classes de la vista estan associades amb algun element visible de la GUI i es comporten com els observadors, descrits abans. A mesura que l'aplicació s'executa, es produeixen canvis en el model. L'usuari veu aquests canvis perquè les vistes són actualitzades en consonància.

Codis d'exemple

[modifica]

Java

[modifica]

Aquí hi ha un exemple que agafa una entrada de teclat i tracta cada línia de l'entrada com un event. Aquest exemple usa les classes de les llibreries java.util.Observer i java.util.Observable. Quan una cadena de caràcters és subministrada a través d'un System.in, el mètode notifyObserver és cridat, que dona ordres d'avisar a tots els observadors(observers) si passa l'esdeveniment, així és com invoca els mètodes 'update' - o en el nostre exemple, ResponseHandler.update(...).

El fitxer myapp.java conté un mètode main() que hauria de ser usat per executar el codi.

/* Nom del fitxer : EventSource.java */

package obs;
import java.util.Observable; //Observable és aquí
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class EventSource extends Observable implements Runnable 
{
 public void run()
 {
 try
 { 
 final InputStreamReader isr = new InputStreamReader(System.in);
 final BufferedReader br = new BufferedReader(isr);
 while(true)
 {
 final String response = br.readLine();
 setChanged();
 notifyObservers(response);
 }
 }
 catch (IOException e)
 {
 e.printStackTrace();
 }
 }
}
/* Nom del fitxer: ResponseHandler.java */

package obs;

import java.util.Observable;
import java.util.Observer; /* this is Event Handler */

public class ResponseHandler implements Observer
{
 private String resp;
 public void update (Observable obj, Object arg)
 {
 if (arg instanceof String)
 {
 resp = (String) arg;
 System.out.println("\nResposta rebuda: "+ resp);
 }
 }
}
/* Nom del fitxer: myapp.java */
/* És el programa principal */

package obs;

public class MyApp
{
 public static void main(String args[])
 { 
 System.out.println("Entra text >");

 // crea un codi d'esdeveniment - llegeix des de stdin
 final EventSource evSrc = new EventSource();

 // crea un observer
 final ResponseHandler respHandler = new ResponseHandler();

 // subscriu l'observer al codi d'esdeveniment
 evSrc.addObserver(respHandler);

 // comença el thread d'esdeveniment
 Thread thread = new Thread(evSrc);
 thread.start();
 }
}