Polimorfirsmo

El polimorfismo es una técnica que permite tratar a un objeto de una clase derivada como si fuese de la clase padre. Polimorfismo significa muchas formas, y justamente se usa este término, porque permite que una variable tenga múltiples formas. La definición misma de la relación de herencia brinda la posibilidad de contar con el polimorfismo, esto es, como una clase derivada es una clase base, siempre que necesitemos una clase base podremos usar una clase derivada. Por ejemplo, si tenemos un método que recibe un objeto de clase Figura, podremos pasarle un objeto de clase Rectángulo o de clase Círculo, ya que tanto el rectángulo como el círculo son figuras. Los lenguajes actuales permiten polimorfismo tanto por herencia como por implementación de interfaces.


La mayor utilidad del polimorfismo radica en que permite programar en un nivel de abstracción superior, ya que podemos especificar los contratos (es decir, qué esperamos en un método o propiedad) utilizando clases abstractas, interfaces o clases base de una gran jerarquía de herencia. Además, como veremos a continuación, mediante el polimorfismo, se logra el máximo nivel de extensibilidad del código, ya que permite encapsular las responsabilidades de los objetos dentro de los objetos mismos y desde afuera trabajar con su abstracción o clase base.

EARLY BINDING VS LATE BINDING El término Binding hace referencia al enlace entre el tipo de dato de una variable y el de su valor. Cuando el tipo de dato que tendrá un valor queda establecido en tiempo de codificación, se denomina EarlyBinding, mientras que cuando el tipo de dato real se conoce recién en tiempo de ejecución, hablamos de Late Binding (enlace tardío). Cuando se explota la técnica de polimorfismo, se usa siempre Late Binding, ya que una variable se declara de una clase, pero en ejecución puede ser de una clase derivada.

Para ilustrar la utilidad del polimorfismo, supongamos que tenemos que escribir un procedimiento que imprima la superficie de una figura, pero sin trabajar con orientación a objetos. Para hacerlo, necesitaremos conocer el tipo de figura y escribir una sentencia de tipo select case para calcular la superficie según el tipo de figura. Veamos algo de código (en C#).

switch(tipoFigura)
{
  case “Cuadrado”:
      Console.WriteLine(base*altura);
      break;
  case “Triangulo”:
      Console.WriteLine((base*altura)/2);
      break;
  case “Circulo”:
      Console.WriteLine(3.14*radio*radio);
      break;
}

El problema con esta porción de código reside en que, cuando agreguemos un nuevo tipo de figura, tendremos que agregar también el caso para hacer el cálculo correspondiente.

Si utilizamos objetos, podemos tener una clase abstracta Figura, con un método abstracto CalcularSuperficie() y sendas clases derivadas para modelar los distintos tipos de figuras. Cada clase derivada es responsable de redefinir el método CalcularSuperficie para adaptarlo a su fórmula de cálculo. De este modo, nues- tro procedimiento para imprimir la superficie se reduce a esto:

public void Imprimir(Figura f)
{
    Console.WriteLine(f.CalcularSuperficie())
}

Cuadrado c;
...
Imprimir( c ); // un cuadrado es una figura

Con esto, cuando necesitemos agregar un nuevo tipo de figura, bastará con escribir la clase correspondiente (heredando de Figura) e implementar el método CalcularSuperficie como corresponda, y no deberemos modificar el procedimiento de impresión.

La técnica de polimorfismo es un poco difícil de entender al comienzo, pero una vez asimilada se convierte en el arma más poderosa de la orientación a obje- tos. El secreto está en entender que, cuando codificamos la llamada a un método de una clase base, debemos tener presente que en ejecución se llamará al método correspondiente de una clase derivada.

LA MAGIA DEL POLIMORFISMO El polimorfismo abre las puertas a un nivel más de abstracción, en el que podemos escribir funcionalidad sin interesar mucho cómo se va a utilizar luego. Un ejemplo claro de esto es el manejo de secuencias de bytes en .Net. El Framework .Net posee una clase llamada Stream, que representa una secuencia de bytes. Luego, hay clases derivadas para leer y escribir de distintos medios, como archivos y llamadas http, y otros. Lo bueno es que muchos métodos reciben como parámetro un Stream, pero podemos pasarle lo que necesitemos. Éste es un claro ejemplo de Poli-
morfismo, con una aplicación práctica en el mundo real.

CONCLUSIONES

La programación orientada a objetos, bien usada, puede ayudarnos a construir software con las características más deseables por todo programador: facilidad de escritura, facilidad de mantenimiento, extensibilidad y reutilización de código. La extensibilidad es la clave para escribir aplicaciones altamente flexibles, ya que permite agregar o modificar comportamiento con muy poco esfuerzo. Es muy importante aprender algunos patrones de diseño e incorporar correctamente los conceptos de abstracción, encapsulamiento y polimorfismo, para no caer en el error de utilizar un lenguaje orientado a objetos para escribir código estructurado.