Polimorfismo | OOP

↑ Me gusta (1)

Este tema podría no ser difícil, vamos a tratarlo con un par de ejemplos bastantes claros para lograr comprenderlo con éxito. La palabra polimorfismo tiene como definición "varias formas" y en programación orientada a objetos puede aplicarse de varias maneras.

Con varias formas quiero decir que un método al interactuar con diferentes objetos tendrá diferentes comportamiento o diferentes resultados.

Ejemplo con clase abstracta

Tenemos una clase madre y algunas clases hijas. La idea es demostrar como cada hija usando el mismo método de su clase madre obtendrá un resultado diferente.

Básicamente un método podrá tener diferentes resultados, al ser esto posible hablamos de polimorfismo.

Vamos a trabajar con los siguientes archivos:

  • Base.php: Clase madre.
  • Admin.php: Clase hija de Base.
  • User.php: Clase hija de Base.
  • Guest.php: Clase hija de Base.
  • index.php: Desde aquí ejecutaremos nuestro proyecto.

Clase abstracta Base.php

<?php

abstract class Base
{ 
    protected $name = ''; 

    private function className()
    {
    	return get_called_class();
    }

    public function login(){ 
        return "Mi nombre es {$this->name}: desde la clase {$this->className()} y me encuentro iniciando sesion... <br>"; 
    }
} 

Tengo a la propiedad $name y el método login() que aprovecharemos desde las clases hijas. Toma en cuenta el concepto de "un método, varios resultados".

Clase hija Admin.php

<?php

class Admin extends Base
{ 
    public function __construct($name)
    {
    	$this->name = $name;
    }
} 

Solo damos de alta el nombre del administrador a través de un constructor.

Clase hija User.php

<?php

class User extends Base
{ 
    public function __construct($name)
    {
    	$this->name = $name;
    }
} 

Mantenemos la misma estructura lógica que con Admin.php. Ambas dicen claramente que pueden dar de alta su nombre en la propiedad definida en la clase abstracta.

Clase hija Guest.php

<?php

class Guest extends Base
{ 
	protected $name = 'Invitado';
} 

Esta sería la clase usada para permitir el paso a usuarios invitados, toma en cuenta que damos de alta a un nombre por defecto que en este caso es "Invitado".

Las tres clases pueden por supuesto usar el método login().

Usemos todo esto en nuestro index.php.

Archivo index.php

<?php 

require_once('Base.php');

require_once('User.php');
require_once('Admin.php');
require_once('Guest.php');

$guest = new Guest(); 
echo $guest->login(); 

$user = new User('Italo Morales'); 
echo $user->login(); 

$admin = new Admin('Lynda Morales'); 
echo $admin->login(); 

## Al ejecutar este código tendremos en pantalla el siguiente mensaje. ##

//Mi nombre es Invitado: desde la clase Guest y me encuentro iniciando sesion...
//Mi nombre es Italo Morales: desde la clase User y me encuentro iniciando sesion...
//Mi nombre es Lynda Morales: desde la clase Admin y me encuentro iniciando sesion... 

Y aquí vemos claramente el concepto...

  • Cada mensaje me dice el nombre de la clase de donde nos conectamos gracias a get_called_class().
  • Los mensajes son diferentes.
  • Veo en cada mensaje al nombre del usuario conectado.
  • Y lo mas importante, en todos los casos uso el método login() y la propiedad $name.

Ejemplo con interfaz

  • Una única interfaz.
  • Varias clases implementan esta interfaz.
  • Cada clase usa y desarrolla como quiera a cada método.

Usar una interfaz, es decir, crearla da como resultado el principio de polimorfismo. Es un recurso válido a la hora de implementar polimorfismo.

¿Qué es una interfaz?: Es un archivo que tiene dentro métodos públicos y de esa manera la clase que la implemente se encargará de desarrollar cada método. Sus características son las siguiente:

  1. La interfaz solo declara los métodos.
  2. Todos los métodos deben ser públicos.
  3. Una interfaz no contiene atributo alguno.
  4. Los métodos allí definidos de desarrollan en la clase que la implemente.
  5. La clase está obligada a usar la estructura definida en la interfaz.
  6. Es posible que una clase implemente varias interfaces.
  7. Una interfaz no se puede instanciar.

¿Aplica el concepto?: De hecho si, porque cada clase que implemente a una interfaz tendrá dentro de si los mismos métodos pero no necesariamente el mismo comportamiento ni el mismo resultado.

Interfaz Search.php

<?php

interface Search 
{
	public function all();
}

Tiene lo necesario, un método público y nada mas.

Clase User.php

<?php

class User implements Search
{ 
    public function all()
    {
    	return "Obteniendo todos los usuarios... <br>";
    }
} 

Tenemos una clase que implementa la interfaz y al hacerlo nos obliga a desarrollar el método all().

Clase Post.php

<?php

class Post implements Search
{ 
    public function all()
    {
    	return "Obteniendo todos los posts... <br>";
    }
} 

Archivo index.php

<?php 

require_once('Search.php');

require_once('User.php');
require_once('Post.php');

$user = new User(); 
echo $user->all();

$post = new Post(); 
echo $post->all();

## Al ejecutar, vemos el siguiente resultado. ##

//Obteniendo todos los usuarios...
//Obteniendo todos los posts... 

Resumen

Cuando hablamos de polimorfismo nos referimos a una capacidad o virtud que tienen los métodos, donde por ejemplo un mismo método puede tener diferentes comportamientos y dar diferentes resultados.

El concepto de polimorfismo trata precisamente de que una misma cosa termina comportándose de diferentes maneras. Aquí hemos visto ejemplos con PHP, toma en cuenta que otros lenguajes podrían tener diferentes método o maneras de implementación. Es probable que en otros lenguajes se logre de igual forma o aplicando una jerarquía de clases y nada mas.

Diferencia entre interfaces y clases abstractas

Esto requiere un post entero, pero te puedo adelantar lo siguiente:

En una interfaz definimos métodos sin códigos, en clase abstracta puede definir métodos y desarrollarlos. Lo interesante es crear una clase abstracta y hacer que esta clase implemente una interfaz. Una interfaz provee los métodos a implementar y una clase abstracta proporciona en la mayoría de los casos una funcionalidad base o por defecto.

Es importante dedicarle un poco mas a este tema en particular, los patrones de diseño proporcionan en estos casos responsabilidades y organización que nos ayuda a entender bien cada rol. Cuando profundicemos en esta área comprenderás realmente cuando usar cada cosa.

  • Manuel Dautt (CTO)