Patrones de Diseño y JavaScript: Observer

Observar el estado de un objeto o sus acciones es una tarea de las más comunes a la hora de desarrollar. Lograr este cometido manteniendo el código desacoplado es la principal premisa de este patrón.

El pattern Observer plantea un escenario donde un objeto (el sujeto) es observado por uno o más suscriptores. En lenguajes como Java este pattern adquiere un poco más de “especificación” ya que implca que el sujeto extienda una clase particular (Observable) así como tambien que los suscriptores implementen una interfaz (Observer). En JavaScript (por suerte o desgracia) la implementación es mucho más libre*.

*No sería muy díficil emular la implementación que Java hace de este pattern, pero a costo de desnaturalizar el desarrollo no tiene demasiado sentido.

De esta manera, el sujeto tiene un método público en el cual se suscriben los observadores. El ejemplo típico en este caso es el del diario y sus suscriptores. Una posible implementación de este ejemplo sin utilizar el patrón en cuestión implicaría llamar a los suscriptores directamente en el diario:

/**
 * Nuestro suscriptor
 */
function Lector(name) {
	this.name = name;
}

Lector.prototype.leer = function(noticia) {
	console.log(this.name + " esta leyendo " + noticia);
}

var douglas = new Lector("Douglas Crockford");
var nicholas = new Lector("Nicholas Zakas");

// Nuestra "clase" Diario
var Diario = function(name) {
	this.name = name;
}

/**
 * Publica una noticia
 */
Diario.prototype.publicar = function(noticia) {
	noticia = noticia + ' | ' + this.name;
	douglas.leer(noticia);
	nicholas.leer(noticia);
	//... así para todos los lectores
}

var DiarioAijoona = new Diario('Aijoona');

DiarioAijoona.publicar('"Eval is evil" | Aijoona');
// Douglas Crockford esta leyendo "Eval is evil" | Aijoona
// Nicholas Zakas esta leyendo "Eval is evil" | Aijoona

Obviamente este tipo de soluciones implican un nivel de acoplamiento muy alto así como también la imposiblidad de agregar nuevos lectores sin modificar el diario.
Por suerte, la implementación del Observer permite evitar dicha problematica

var Diario = function(name) {
	this.name = name;
	this.suscriptores = [];
}

/**
 * Publica una noticia
 */
Diario.prototype.publicar = function(noticia) {
	noticia = noticia + ' | ' + this.name;
	for(var i = 0, l = this.suscriptores.length; i < l; i++) {
		this.suscriptores[i].leer(noticia);
	}
}

/**
 * Suscribe un lector al diario
 */
Diario.prototype.suscribir = function(lector) {
	this.suscriptores.push(lector);
}

var DiarioAijoona = new Diario('Aijoona');

// Suscribimos los lectores
DiarioAijoona.suscribir(douglas);
DiarioAijoona.suscribir(nicholas);

DiarioAijoona.publicar('Eval is evil');
// Douglas Crockford esta leyendo Eval is evil | Aijoona
// Nicholas Zakas esta leyendo Eval is evil | Aijoona

De igual manera se pueden suscribir los lectores a varios diarios:

var Diario20 = new Diario('Diario 2.0');

// Suscribimos los lectores al nuevo diario
Diario20.suscribir(douglas);
Diario20.suscribir(nicholas);

// nueva tirada
Diario20.publicar('Browser sniffing is evil');
DiarioAijoona.publicar('Not is not');

En definitiva, la implementación de este pattern es bastante sencilla, requiriendo unicamente un método para la suscripción de los observers y otro paral a notificación de los mismos. A diferencia de lo expuesto en estos ejemplos, es práctica común suscribir funciones o métodos en lugar de objetos.

Versiones más avanzadas de este pattern pueden incluir suscripción para eventos específicos, métodos de baja de suscriptores, etc.

Leer más:



3 views shared on this article. Join in...

  1. Hicham dice:

    Me ha quedado mas claro con tu explicación. Gracias

  2. miguelangeltorresfp dice:

    Cuando las cosas se explican bien pueden llegar a ser muy sencillas.

    Gracias !!!

  3. Daniel dice:

    Gracias!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Comment

You may use these tags : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>