Delegación vs Herencia

Angus Croll del blog Javascript, Javascript parte de parafrasear a James Gosling (autor original de Java) para exponer la delegación de funcionalidad en JavaScript.

Bill Venners: When asked what you might do differently if you could recreate Java, you’ve said you’ve wondered what it would be like to have a language that just does delegation.
James Gosling: Yes.

Tecnicamente hablando, la delegación es la reutilización de código mediante llamadas a funciones no nativas de los objetos. En el caso de Javascript esto se puede lograr con mucha facilidad gracias a los métodos call y apply del objeto Function.

Esto lo expone mediante el código expuesto a continuación (copiado textualmente, solo se agregaron comentarios):

/**
 * Construye rectangulos
 *
 * @class
 */
var Rectangle = function(left, top, length, width, options) {
	this.left = left;
	this.top = top;
	this.length = length;
	this.width = width;
    if (options) {
    	this.color = options.color;
    	this.border = options.border;
    	this.opacity = options.opacity;
    	//... etc.
    }
}

/**
 * Verifica si el rectangulo colisiona con el objeto
 * recibido
 *
 * @param {Object}
 * @returns {Boolean}
 */
Rectangle.prototype.overlaps = function(another) {
	var r1x1 = this.left,
	    r1x2 = this.left + this.width,
	    r1y1 = this.top,
	    r1y2 = this.top + this.height,
	    r2x1 = another.left,
	    r2x2 = another.left + another.width,
	    r2y1 = another.top,
	    r2y2 = another.top + another.height;	    

    return (r1x2 >= r2x1) && (r1y2 >= r2y1) && (r1x1 <= r2x2) && (r1y1 <= r2y2);
}
// Instanciamos
var myRectangle = new Rectangle(10, 10, 30, 20, {color:'#FAFAFA', opacity:0.7});
// Y verificamos
myRectangle.overlaps(myOtherRectangle);

Hasta ahí tenemos una implementación típica del OOP “prototípico” de Javascript. Ahora, volviendo al tópico, imaginemos un escenario donde otro tipo de objeto (Dashlet según Angus) requiere de la misma funcionalidad.

En un lenguaje OOP popular como Java esto se solucionaría extendiendo la clase Rectangle o implementando alguna interfaz puntual.
La crítica que encuentra a este punto esta dada por el hecho de que esta herencia agregaría atributos y comportamientos irrelevantes (e innecesarios)*. Entonces, es aquí donde se presenta la oportunidad de “delegar” comportamiento.

*Obviamente se podría modificar la jerarquía de clases y herencia para minimizar e incluso hacer desaparecer esta problematica, pero no es tema de este post.

Esto termina en un código poco agraciado, pero aún funcional (suponiendo que los objetos dashlet contengan los atributos utilizados en la función).

Rectangle.prototype.overlaps.call(dashlet1, dashlet2);

Si bien el resultado es indiscutible, en lo personal este tipo de construcciones no me parecen lo suficientemente ventajosas como para hacerlas práctica habitual. Creo que la flexibilidad que ofrece este lenguaje permite soluciones más elegantes, legibles y no mucho menos performante.

El resto del post habla de las funciones nativas génericas, que basicamente permiten trabajar sobre objetos de distinto tipo a su clase. Para ser más claros referirse al siguiente código (nuevamente copiado textualmente).

"".trim.apply([" a","b "]).split(",");
//["a","b"]

"".toLowerCase.apply(["DIV","H1","SPAN"]).split(",");
//["div","h1","span"]

"".match.call(["a16","b44","b bar"],/[a-z][0-9]+/g);
//["a16", "b44"]

"".replace.call(
	['argentina','brazil','chile'],
	/\b./g, function(a){ return a.toUpperCase(); }
).split(',');
//['Argentina',"Brazil","Chile"]

Acá paro la pelota, y pregunto ¿qué tan predecible es el comportamiento en cada uno de los ejemplos presentados?

En mi opinión, poco poco.

Leer más:



Deja un comentario

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

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>