Modelo de objetos en PHP5 - Herencia

La herencia es otra de las características fundamentales de la programación orientada a objetos. El objetivo final de la herencia de clases es la reutilización de código.

 

Herencia básica

La idea básica de diseño es que primero se construyen las clases más genéricas (con el mayor grado de abstracción posible) y a partir de éstas se derivan las clases más especializadas.

Como la clase derivada hereda las características y la funcionalidad de la clase base, cada nuevo nivel en la jerarquía de clases implicará un grado más de especialización.

Por ejemplo, la clase Vehiculo de ejemplos anteriores contiene características y funcionalidad comunes a casi todos los vehículos. Si se necesita trabajar con un coche (un coche es un tipo especializado de vehículo) se puede derivar la clase Vehiculo para conseguir la clase Coche, y añadir a esta nueva clase las características específicas de los coches, así como la funcionalidad necesaria.

//// un coche 'es' un vehiculo
class Coche extends Vehiculo
{

public
$capacidadMaletero;
public
$numeroPuertas;

//// constructor
function __construct($potencia,$peso,$puertas=5)
{
$this->potencia = $potencia;
$this->peso = $peso;
$this->numeroPuertas = $puertas;

return
true;
}

}

//// creamos un coche (60 CV, 1500 Kg)
$objCoche = new Coche(60,1500);

//// calculamos su relacion peso/potencia
echo $objCoche->relacionPesoPotencia();

Se puede ir más allá y modelar un Fórmula 1, que es un tipo especializado (muy especializado) de coche:

//// un formula 1 'es' un coche
class Formula1 extends Coche
{
public
$versionDeMotor;
public
$controlDeTraccionActiva;

function
__construct($potencia,$peso)
{
$this->potencia = $potencia;
$this->peso = $peso;

$this->numeroPuertas = 0;
$this->capacidadMaletero = 0;

return
true;
}
}

//// creamos un coche (900 CV, 600 Kg)
$objFerrari = new Formula1(900,600);

//// calculamos su relacion peso/potencia
echo $objFerrari->relacionPesoPotencia();

La funcionalidad de la clase Vehiculo es heredada por la clase Coche, la de Coche por Formula1... No es necesario volver a implementar dicha funcionalidad para cada nuevo tipo de objeto, simplemente la reutilizamos.

Está claro que cuanto mejor sea el diseño de una jerarquía de clases mayor será su rendimiento (en este contexto, rendimiento significa productividad a la hora de generar una solución que resuelva un problema de la forma más rápida, robusta y eficiente posible).

 

Métodos y atributos finales

En ocasiones es útil tener cierto control sobre la forma en que las clases derivadas sobrescriben ciertos métodos de la clase base (puesto que podrían cambiar la funcionalidad para la que fue diseñada inicialmente la clase). Por ejemplo, sería poco lógico que el método relacionPesoPotencia() de la clase Coche calcule en realidad el peso del coche en la Luna...¿?

Con el cualificador 'final', el diseñador de una clase puede obligar a que un determinado método no se pueda definir en las clases derivadas y sustituya (override) la funcionalidad que proporciona la clase base. Por ejemplo:

class Vehiculo
{
//// $peso se declara como atributo final de la clase
final $peso;

protected
$potencia;
private
$relacionPesoPotencia;

function
__construct($potencia,$peso)
{
$this->potencia = $potencia;
$this->peso = $peso;

return
true;

}

//// se declara como metodo final de la clase
final function relacionPesoPotencia()
{
if (
$this->potencia>0)
{
$this->relacionPesoPotencia = ($this->peso/$this->potencia);
}else
{
$this->relacionPesoPotencia = -1;
}

return
$this->relacionPesoPotencia;
}

}


class
Moto extends Vehiculo
{
public
$cilindrada;
public
$tipoMotor;

//// ERROR: se redefine el atributo $peso
//// (declarado como final)
public $peso;
protected
$potencia;
private
$relacionPesoPotencia;

function
__construct($potencia,$peso)
{
$this->potencia = $potencia;
$this->peso = $peso;

return
true;

}
//// fin de "__constructor"

//// ERROR: se redefine el metodo relacionPesoPotencia()
//// (declarado como final)
function relacionPesoPotencia()
{
return
Vehiculo::relacionPesoPotencia();
}

}

 

Felipe Fernández Perera : Google+