Luego de casi un año sin pasarme por este espacio, vuelvo a postear algo, esta vez relacionado con los patrones de diseño, especificamente con el Patron Observador u Observer(en Ingles).
El patrón Observer, no es más que un manejador y despachador de eventos, en el cual unos o varios “observadores” se suscriben a un “sujeto”, el cual les “notifica” cuando un evento es llevado a cabo, de tal forma que dichos observadores puedan realizar una determinada operación.
Tenemos entonces en este patron 2 elementos (clases) principales, el Sujeto o Subject y el (los) Observador(es) o Observer(s).
Empezemos por el Sujeto, el cual tendra un metodo de registro de Observadores y un metodo que notificara a todos ellos cuando cierto evento se ha presentado, en PHP:
class Subject {
var $m_Observers;
function registerObserver($observer) {
$this->m_Observers[count($this->m_Observers)]=$observer;
}
function notifyObservers() {
foreach($this->m_Observers as $k => $observer){
$observer->notify();
}
}
Sobre la funcion registerObserver no hay mucho que decir, simplemente se encarga de agregar a un array el Objeto observador que estara esperando por una notifacion de parte del sujeto cuando X o Y evento se presente.
La funcion notifyObservers() sera la encargada de notificar a los Observers el evento, los cuales a su vez se encargaran de llevar a cabo tareas propias para ese evento.
Bien, hasta aqui “todo claro”(?), ahora es momento de definir la clase Observer, dicha clase debe tener como minimo el metodo notify, ya que ese metodo es el que llama el Subject para notificar el evento. El elemento Observer lo voy a definir de tal forma que se pueda establecer una funcion X de una clase Y que sera la encargada de procesar el evento reportado. Es decir, para construir un Observer hay que decirle, que instancia de que clase va a procesar el evento y con que funcion de dicha clase.
class Observer {
//La instancia de la clase que va a procesar el evento
var $m_Handler;
//El nombre de la funcion que va a procesar el evento
var $m_Function;
function Observer($handler, $function) {
$this->m_Handler = $handler;
$this->m_Function = $function;
}
}
Suponiendo que queremos que el evento X sea procesado por la funcion onProcesar de la clase MyClase. En este caso, nuestro objeto observador debe ser creado de la siguiente manera:
$observer = new Observer(new MyClase(), 'onProcesar');
Esta claro, que hay que crear una instancia de la clase MyClase si queremos llamar luego a su funcion miembro ‘onProcesar’, si este Objeto ya ha sido creado anteriormente, solo habria que pasar la variable y el nombre de la funcion.
Ahora bien, como hacemos para que el Sujeto pueda ejecutar dicha funcion cuando se presente un evento?, lo primero que debemos hacer es definir la funcion notify en la clase Observer, que es en definitiva el metodo que invoca el Subject para notificar sobre un evento a un determinado Observer. Es en el cuerpo de esta funcion notify, donde debemos invocar a la funcion registrada para manejar el evento.
//La siguiente funcion hace parte de la clase Observer
function notity(){
call_user_func(array($this->m_Handler,$this->m_Function));
}
La funcion call_user_func que provee PHP nos ayuda a hacer lo que queriamos de una forma bastante simple, dicha funcion recibe como parametros un Objeto y un nombre de Funcion que debe ser miembro de dicho objeto, y hace el llamado correspondiente a dicha funcion.
Ahora si, podemos hacer un test de nuestro Observer y ver como funciona realmente. Vamos a registrar 2 Observer a un Subject, cada Observer ejecutara una funcion diferente que perteneceran a su vez a dos clases diferentes. Veamos:
class ClaseExtra {
function imprimir (){
print "Hola Mundo desde la ClaseExtra";
}
class Test (){
function hola(){
print "Hola Mundo desde la clase Test";
}
function runTest(){
$subject = new Subject();
$extra = new ClaseExtra();
//A continuacion creo un observer que ejecutara la funcion "hola"
//de la clase Test cuando se presente el evento
$observerLocal = new Observer($this, 'hola');
//A continuacion creo un observer que ejecutara
//la funcion "imprimir" del objeto extra de tipo ClaseExtra
$observerExtra = new Observer($extra, 'imprimir');
//Ahora registro los Observers
$subject->registerObserver($observerLocal);
$subject->registerObserver($observerExtra);
//Por ultimo voy a generar un evento, el cual disparará
//las funciones que se encargaran de procesarlo.
$subject->notifyObservers();
}
}
//Corremos el Test
$t = new Test();
$t->runTest();
Una vez que ejecutemos el codigo anterior el resultado que tendremos sera la impresion en pantalla de los mensajes:
Hola Mundo desde la clase Test
Hola Mundo desde la claseExtra
Muy bien, bastante simple todo, pero tambien bastante util.
Es posible tambien pasar parametros a la funcion que se procesa el evento, para ello PHP tambien nos ayuda y nos provee la funcion call_user_func_array la cual recibe ademas parametros que pueden ser enviados a la funcion.
NOTA: Este post esta orientado a personas que estan familiarizadas con los patrones de diseño (concretamente con el patron Observer), es muy posible que muchos no entiendan mucho de lo que aquí expongo.
Recomiendo visitar el link de la wikipedia en Ingles, donde explican con un poco mas de detalle el patron y dan ejemplos de implementaciones en varios lenguajes de programacion.









[...] Patron de diseño Observer en PHP arturoweb.wordpress.com/2010/03/08/patron-de-diseno-observer… por garciasegu hace 3 segundos [...]
Muy interesante, andaba ganduleando con el Observer pero por fin encuentro una explicación rápida y concisa. Ahora la pregunta: ¿se podría sustituir la llamada a call_user_func por alguna construcción nativa del lenguaje? O mejor aún ¿en vez de callbacks utilizar funciones anónimas o closures introducidas en PHP 5.3?
Hola Walter, el call_user_func lo uso para llamar a cualquier funcion sin importar en que clase se encuentre. Lo cual hace que sea mucho mas flexible y generico el Observer.
Lo que tu propones lo haria no modificando el call_user_func sino escribiendo la funcion que se llama mediante call_user_func, es decir creando tu propia funcion que haga el llamado a las “construcciones nativas” de las que hablas. En mi ejemplo seria modificar las funciones “imprimir” y “hola” o creando tu propia funcion “mifuncion” y usarla en la creacion del objeto Observer.
Saludos!
Información de BlogESfera.com……
Puedes valorar este post en BlogESfera.com haciendo click aqui….
Yo seguí http://www.vertutoriales.com/index.phpphp/tag/php/ y sirvio
Un libro se lee mejor con Sprite y el arte se disfruta más con su nuevo graffiti http://bit.ly/SGraffitiCentroMayor
que buen talento para la programacion, algo dificil de entender al principio productormusical