Zootropo

Diario del mundo geek.

miércoles, julio 28, 2004

Javascript: Polimorfismo

La palabra polimorfismo se refiere al hecho de tener varios métodos con el mismo nombre y la misma implementación. En la programación orientada a objetos el polimorfismo a considerar es el polimorfismo de clases (también pueden implementar otros tipos pero no nos interesa ahora), que consiste en que un objeto de una clase derivada es al mismo tiempo un objeto de la clase padre, de forma que allí donde se utilice un objeto de la clase padre también se puede utilizar uno de la clase hija.

Por ejemplo si tenemos una clase instrumento de la que derivan guitarra y bajo; las guitarras y los bajos son instrumentos así que se puede asociar una referencia instrumento a un objeto de tipo guitarra, porque al fin y al cabo dado que guitarra tiene definidos todos los métodos y propiedades que tenía instrumento (porque los ha heredado) no nos dará ningún problema, lo único que puede cambiar es que se halla sobreescrito la implementación de alguna función.

Por ejemplo supongamos un método tocar en instrumento que imprime en pantalla "Toco un instrumento" y que se sobreescribió en la clase guitarra para que escribiera "Toco una guitarra". Si creamos un objeto de la clase guitarra pero la enlazamos a una referencia de la clase instrumento, entonces guitarra se comportará como un objeto de la clase instrumento, olvidando que tiene otros métodos y propiedades que no sean los que estaban definidos en la clase instrumento. Sin embargo si llamamos a la función tocar de este objeto, se imprimirá el mensaje "Toco una guitarra", en lugar de "Toco un instrumento". Polimorfismo.

Esto es posible gracias a que se ha utilizado un enlace dinámico o tardío, es decir, se asigna a cada una de las llamadas su implementación correspondiente en tiempo de ejecución, en lugar de hacerlo durante la compilación (enlace estático) que provocaría que quede fijado, con lo que en el ejemplo anterior al ver una referencia de tipo instrumento, la enlazaría con la implementación del método en instrumento, no en guitarra.

Dado que Javascript no tiene herencia basada en clases, muchas veces se considera equivocadamente que Javascript no soporta polimorfismo, porque se confunde polimorfismo con polimorfismo de clases. Vamos a ver un ejemplo. Supongamos una empresa dividida en departamentos, que a su vez puede estar dividida en otros subdepartamentos y así sucesivamente. Tenemos entonces un objeto departamento que a su vez puede incluir otros departamentos, que también pueden incluir otros,... El objetivo es calcular el sueldo total a pagar de todos los trabajadores. El sueldo de un departamento es la suma de todos los sueldos de los objetos que lo conforman, ya sean trabajadores u otros departamentos.

Para calcular el sueldo total de la empresa podríamos recorrer la matriz que representa la empresa comprobando si el objeto es un departamento o un empleado y llamando al método correspondiente según el tipo de objeto. Sin embargo, podemos aprovecharnos del polimorfismo. Si llamamos al método de la misma forma, por ejemplo calcularNomina, y recorremos el array llamando a calcularNomina para cada objeto, el intérprete se encargará de ver si la implementación que le corresponde es la de departamento o la de empleado:

<script>
function departamento(){
this.personal = new Array();
this.anyadir = anyadir;
this.calcularNomina = calcularNominaDept;
}

function empleado(nomina){
this.nomina = nomina;
this.calcularNomina = calcularNominaEmpl;
}

function anyadir(objeto){
this.personal.push(objeto);
}

function calcularNominaDept(){
var nomina = 0;
for(var i = 0; i < this.personal.length; i++){
nomina += this.personal[i].calcularNomina();
}
return nomina;
}

function calcularNominaEmpl(){
return this.nomina;
}

empresa = new departamento();
empresa.anyadir(new empleado(200));
empresa.anyadir(new empleado(100));
contabilidad = new departamento();
contabilidad.anyadir(new empleado(120));
empresa.anyadir(contabilidad);
document.write(empresa.calcularNomina());
</script>

En resumen, tenemos varios métodos con el mismo nombre y distinta implementación y el intérprete se encarga de decidir como enlazarlos según el caso.