Observer

Patrón de Diseño Observador
Información sobre la plantilla
Observador.png

Patrón de Diseño Observador, su traducción en inglés:"Observer" también conocido como "spider" define una dependencia del tipo uno-a-muchos entre objetos, de manera que cuando uno de los objetos cambia su estado, el observador se encarga de notificar este cambio a todos los otros dependientes. Es fácil de entender y esta clasificado como un patrón de comportamiento.

Objetivo

El objetivo de este patrón es cuando tenemos varios objetos observadores y un objeto observado por los observadores.Los observadores necesitan saber cuando se produce un cambio en el objeto observado. El primer planteamiento que se puede pensar, es que haya un proceso/thread/tarea/… que se encargara de que los observadores vayan haciendo peticiones periódicamente el estado del objeto observado, para así detectar cuando sucede el cambio.

Problema

El problema surge cuando el intervalo entre petición es muy corto, o hay demasiados objetos observadores haciendo peticiones al objeto observado, o es necesario que el observador sea notificado inmediatamente después del cambio del objeto observado.

Solución

La solución que se aplicaría usando el patrón Observador, trata de que los objetos observadores se añadan a una lista de objetos, y el objeto observado notificará el cambio a todos los objetos de esta lista cuando se produzca el cambio. De esta manera, se produce un cambio de papeles: el observador que tenía la tarea de estar pendiente del cambio, ahora esta a la espera de que el observador le avise.

Implementacion en PHP

La implementación consiste en crear objetos observables que mantienen una lista de observadores y les notifica a éstos de cualquier cambio en su estado,normalmente llamando a uno de sus métodos. El patrón suele utilizarse para implementar un sistema de manejo de eventos distribuido, por ejemplo construir un sistema de logging en el que registramos el observador (clase que se ocupa de escribir el log) en cada objeto que queramos que envíe mensajes al log.

Ejemplo de implementación

En primer lugar creamos la clase abstracta de la que heredarán las clases observables, y el interfaz que implementarán los observadores.


<?php abstract class Observable{
       protected $observers;
       function __construct(){
               $this->observers = array();
       }

       public function registrarObserver($observer){
               if(!in_array($observer, $this->observers)){
                   $this->observers[] = $observer;
               }
       }

       public function deregistrarObserver($observer){
               if(in_array($observer, $this->observers)){
                   $key = array_search($observer, $this->observers);
                   unset($this->observers[$key]);
               }
       }

       abstract public function notificarObservers();

}

interface Observer{
public function notificar($sender, $params);
}
?>
<?php class MiObservable extends Observable{

       public function __construct(){
               parent::__construct();
       }

       public function notificarObservers(){
               foreach ($this->observers as $observer) {
                       $observer->notificar($this, $this->param);
               }
       }

       public function Evento($texto){
               $this->param = $texto;
               $this->notificarObservers();
       }
}
class Log implements Observer{
       public function notificar($sender, $param){
               echo get_class($sender)." envio $param a las ".date('h:i:s', time())."
"; } } class SalvarLog implements Observer{ public function notificar($sender, $param){ echo "Guardando en BD $param enviado por ".get_class($sender)."...

"; } } ?>

Para utilizarlo, instanciaremos las clases y registraremos los observadores de esta manera:

<?php
$obj = new MiObservable();
$obj->registrarObserver(new Log());
$obj->registrarObserver(new SalvarLog());

$obj->Evento('Test 1');
sleep(1);
$obj->Evento('Test 2');

$obj->deregistrarObserver(new SalvarLog());
$obj->Evento('Test 3');
?>

Fuentes