El patrón observador es sencillo de entender y más fácil de ver cuando es necesario.
Tendremos 2 objetos, por un lado el observador y por el otro el observado.
El observador debe ver cuando el observado realiza algún cambio y tomar determinada acción.
El modelos antiguos el observador miraba constantemente al observado para ver cuando éste cambiada, el problema de éste modelo es que había que mirar constantemente al observado para ver cuando realizaba una modificación.
Con el patrón observador cambiaron un poco los roles, tenemos el mismo esquema, observador y observado, la diferente es que observador no estará “mirando” todo el tiempo a observado para ver cuando hay un cambio, sino que éste último le avisará mediante una notificación a su observador cuando haga efectivo dicho cambio.
En un ejemplo de la vida cotidiana:
- Un padre ve como su niño anda en bicicleta, él esta ateto el 100% del tiempo mirando que no se golpee, sí un accidente ocurriese el padre se enteraría al instante ya que ve lo que sucedió. Aquí vemos como el observador está monitoreando constantemente al observado.
- Un niño esta andando en bicicleta y al tener un incidente éste avisa a su padre. Aquí vemos como el observado notifica a su observador en determinado evento.
Vamos a los papeles, aquí el código
Separaremos las clases de la implementación, estará en 2 archivos, modelo.php e implementacion.php
<?php //modelo.php abstract class observable{ protected $observadores; public function __construct(){ $this->observadores = array(); } public function registrarObservador($observador){ if(!in_array($observador, $this->observadores)){ array_push($this->observadores, $observador); } } public function eliminarObservador($observador){ if(in_array($observador, $this->observadores)){ $key = array_search($observador, $this->observadores); unset($this->observadores[$key]); } } abstract public function notificarObservador(); } interface observador{ public function notificar($remitente, $parametro); } class Usuario extends observable{ public $parametro; public function __construct(){ parent::__construct(); } public function notificarObservador(){ if(count($this->observadores) > 0){ foreach ($this->observadores as $observador){ $observador->notificar($this, $this->parametro); } }else{ echo "No hay observadores<br />"; } } public function setParametro($value){ $this->parametro = $value; $this->notificarObservador(); } public function getParametro(){ return $this->parametro; } } class Log implements Observador{ public function notificar($remitente, $parametro){ echo "El objeto " . get_class($remitente) . " ha cambiado la propiedad `parametro` al valor de '$parametro' a las " . date('H:i:s', time()) . "<br />"; } } class LogDB implements Observador{ public function notificar($remitente, $parametro){ echo "El objeto " . get_class($remitente) . " ha guardado la propiedad `parametro` por valor de '$parametro' en la base de datos<br />"; } } class LogEmail implements Observador{ public function notificar($remitente, $parametro){ echo get_class($remitente) . " notifica un cambio y ha sido enviado por mail<br />"; } } ?>
Vamos a dividir la explicación de modelo.php en 4
- Definimos una clase abstracta observable, todas las clases que extiendan de ésta podrán ser observadas, también podrán registrar y eliminar observadores y deberán implementar la notificación
- Definimos una interfaz observador, todos los observadores implementarán ésta interfaz y estarán obligadas a poseer el método notificar, sí bien éste paso podría pasarse por alto es una muy buen practica
- Definimos la clase que va a ser observada, en este ejemplo usamos una clase llamada Usuario y ésta notificará a sus observadores cuando la propiedad método haya cambiado su valor
- Por último definimos los observadores que implementan la interfaz y todos poseen el método notificar, aquí definimos 3 observadores, un muestra un mensaje, otro guarda en base de datos y el último da un aviso por mail
Aquí la implementación, veremos diferentes maneras en las implementaciones.
Implementación 1:
<?php //implementacion1.php $ob = new Usuario; $ob->setParametro('Daniel'); echo "Parametro: " . $ob->getParametro() . "<br />"; ?>
<!--resultado--> No hay observadores Parametro: Daniel
Implementación 2:
<?php //implementacion2.php $ob = new Usuario; $ob->registrarObservador(new Log); $ob->setParametro('Marcos'); echo "Parametro: " . $ob->getParametro() . "<br />"; ?>
<!--resultado--> El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Marcos' a las 18:40:46 Parametro: Marcos
Implementación 3:
<?php //implementacion3.php $ob = new Usuario; $ob->registrarObservador(new Log); $ob->registrarObservador(new LogDB); $ob->registrarObservador(new LogEmail); $ob->setParametro('Federico'); echo "Parametro: " . $ob->getParametro() . "<br />"; ?>
<!--resultado--> El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Federico' a las 18:42:08 El objeto Usuario ha guardado la propiedad `parametro` por valor de 'Federico' en la base de datos Usuario notifica un cambio y ha sido enviado por mail Parametro: Federico
Implementación 4:
<?php //implementacion4.php $ob = new Usuario; $ob->registrarObservador(new Log); $ob->registrarObservador(new LogDB); $ob->registrarObservador(new LogEmail); $ob->setParametro('Hugo'); echo "Parametro: " . $ob->getParametro() . "<br />"; sleep(2); $ob->eliminarObservador(new LogDB); $ob->setParametro('Diego'); echo "Parametro: " . $ob->getParametro() . "<br />"; ?>
<!--resultado--> El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Hugo' a las 18:43:45 El objeto Usuario ha guardado la propiedad `parametro` por valor de 'Hugo' en la base de datos Usuario notifica un cambio y ha sido enviado por mail Parametro: Hugo El objeto Usuario ha cambiado la propiedad `parametro` al valor de 'Diego' a las 18:43:47 Usuario notifica un cambio y ha sido enviado por mail Parametro: Diego