Los Singletons son el mal reencarnado. El pecado original fueron las clases estáticas

No sé si alguno de vosotros ha tenido alguna vez fuertes discusiones con algun colega programador sobre este tema, yo sí. Demasiadas. ;P

Y es que siempre resulta difícil explicarle a alguien por qué algo que es cómodo es malo. En fin, qué le vamos a hacer pero la experiencia nos ha demostrado a todos, creo, que normalmente las mejores soluciones no son las más fáciles… y punto. Pero como el sentido común no es el más común de los sentidos me voy a explicar.

El patrón Singleton facilita dos cosas:

  1. Control sobre la instaciación de una clase. Sólo permite crear una instancia (Esto suena bien)
  2. Un punto de acceso global a la única instancia de esa clase y por tanto a toda su funcionalidad (Suena todavía mejor)

Pero que algo suene bien o todavía mejor no es un argumento para utilizar una técnica a diestro y siniestro. Sobre todo cuando no se piensa en todas las implicaciones de esa melodía que parece sonar tan bien.

Continue reading →

Interfaces en Javascript

Una de las primeras cosas que he echado de menos en javascript son las interfaces. Ya sé que la mayoría de los programadores de Javascriot no sabéis lo que son. Seguramente en algún rato libre escribiré sobre ellas con más detalle.
De momento, baste decir que son tremendamente útiles cuando ouno intenta implementar patrones de diseño como el Strategy o el Command. Y son, de hecho, una de las piedras angulares de la programación orientada a objetos en cualquier lenguaje.
En javascript no existen :-(. Pero hay formas, más o menos retorcidas, de implementar algo parecido. (Ver Pro Javascript Design Patterns, de Ross Harmes y Dustin Diaz, Apress 2007).

[sourcecode language=»javascript» wraplines=»false»]
// Constructor.
var Interface = function(name, methods) {
if(arguments.length != 2) {
throw new Error("Interface constructor called with " + arguments.length +
"arguments, but expected exactly 2.");
}
this.name = name;
this.methods = [];
for(var i = 0, len = methods.length; i < len; i++) {
if(typeof methods[i] !== ‘string’) {
throw new Error("Interface constructor expects method names to be "
+ "passed in as a string.");
}
this.methods.push(methods[i]);
}
};
// Static class method.
Interface.ensureImplements = function(object) {
if(arguments.length < 2) {
throw new Error("Function Interface.ensureImplements called with " +
arguments.length + "arguments, but expected at least 2.");
}
for(var i = 1, len = arguments.length; i < len; i++) {
var interface = arguments[i];
if(interface.constructor !== Interface) {
throw new Error("Function Interface.ensureImplements expects arguments"
+ "two and above to be instances of Interface.");
}
for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) {
var method = interface.methods[j];
if(!object[method] || typeof object[method] !== ‘function’) {
throw new Error("Function Interface.ensureImplements: object "
+ "does not implement the " + interface.name
+ " interface. Method " + method + " was not found.");
}
}
}
};

[/sourcecode]

Para utilizarlas hay que instanciar primero la interfaz, pasando los métodos que ha de implementar cualquier clase que la utilice:

[sourcecode language=»javascript» wraplines=»false»]

var IPajaro =  new Interface(‘IPajaro’, [‘anda’, ‘vuela’, ‘diAlgo’]);

[/sourcecode]

Cuando creemos la clase Pato deberemos implementar, como mínimo, los métodos especificados en el Array del segundo parámetro:

[sourcecode language=»javascript» wraplines=»false»]

var Pato = function () { // Implementa la interfaz IPajaro
var cuack = function () {
// Implementación del método cuack
}

this.anda = function () {
// Implementación del método andar
};
this.nada = function () {
// Implementación del método nadar
};
this.vuela = function () {
// Implementación del método volar
};
this.diAlgo = cuack;
}
[/sourcecode]

¿Por qué querríamos hacer esto? Porque si queremos hacer nuestro código realmente flexible querremos utilizar cualquier tipo de pájaro en nuestro código, y querremos comprobar que cuando usemos un pájaro implemente realmente los métodos que queramos lanzar.
Si no utilizamos la interfaz, la única manera eficiente de hacerlo es comprobar si el presunto objeto pajaro es una instancia de Pato, o de Aguila, o de Cuervo,… mal asunto, porque podemos tener muchos pájaros definidos, ¿Los vamos a comprobar todos? ¿Tendremos que escribir código específico para cada uno de ellos cada vez que queramos utilizar una de sus instancias?…

Para eso sirve una interfaz: establece un contrato para la API de un conjunto de objetos con características comunes, de forma que todos los que implementan la misma se puedan utilizar indistintamente en las partes de nuestro código que no necesiten saber cuál de ellos es exactamente. Así que si queremos hacer volar cualquier pájaro (y en nuestro caso concreto lo que tenemos es un pato) sólo tendremos que hacer lo siguiente:

[sourcecode language=»javascript» wraplines=»false»]
var vuelaPajaro = function (pajaro) {
// Lanza un error si pajaro no implementa los métodos de IPajaro
Interface.ensureImplements(pajaro, IPajaro);
pajaro.vuela();
};

var patitoFeo = new Pato();

vuelaPajaro(patitoFeo);
[/sourcecode]

De esta forma la implementación de la función vuelaPajaro() no depende de si el pájaro es un Aguila, un Pato, un Grajo, etc. y al mismo tiempo nos estamos asegurando de que al menos implementa los métodos necesarios para poder utilizarlo como un pájaro.

Yet another slideshow

Debe de haber cientos de códigos para descargar y hacerse un slideshow en flash. Pero, en parte porque quería practicar mis recién aprendidos patrones de diseño y en parte porque en Le Petit Kolhos necesitábamos uno que pudiera funcionar desde dentro de wordpress.com y usando su gestor de contenidos, decidí hacerme el mio. Esto último ha sido un poco trucoso pero está conseguido.
Aquí teneis una pequeña demostración:
[gigya src=»http://www.glantucan.com/LPKslideshow.swf» width=»260px» height=»226px» flashvars=»duration=5&transitionTime=.5&basePath=http://lepetitkolhos.files.wordpress.com/2010/11/&playList=ss_adultos2.jpg;ss_esquinica.jpg;ss_adultos.jpg;ss_plasti04.jpg;ss_plasti03.jpg;ss_plasti01.jpg;ss_plasti02.jpg;ss_adultos4.jpg;ss_fritanga.jpg;ss_medioambiental.jpg;ss_medioambiental2.jpg;ss_adultos5.jpg;ss_talleradultos01.jpg» wmode=»transparent»]