Programación Orientada a Objetos (VI)

Ya es mucha la soltura que tenemos con la Programación Orientada a Objetos, y estamos familiarizados con los conceptos fundamentales. En este artículo vamos a seguir ahondando en el tema de la herencia, viendo como podemos finalizar clases y métodos para que no puedan extenderse más.

Es una técnica que a muchos les parece superflua, ya que, si no quieres extender una clase pues, sencillamente, no la extiendes, y punto. Eso está muy bien, cuando tu proyecto sólo lo tocas tú, y sabes lo que se puede extender y lo que no. Sin embargo, en la mayoría de las ocasiones en un escenario real esto no es así. Tú creas una clase para tal o cual cosa, y luego esa clase se implementa en un proyecto que está desarrollando otra persona. Es entonces cuando se hace necesario, en muchos casos, poner límites a las cosas, a lo que se puede hacer y lo que no. De eso vamos a ocuparnos en este artículo.

FINALIZANDO CLASES

Esta es una técnica que consiste en limitar el alcance de una clase, de modo que no pueda ser extendida en otras, es decir, que no se puedan crear otras clases que hereden de la tuya. Para ello, simplemente, declaramos nuestra clase con la palabra reservada final.

Vamos a empezar reproduciendo un ejemplo de herencia que ya vimos en un artículo anterior de esta serie, ligeramente modificado para que te des cuenta de hasta que punto la herencia de clases puede llegar a ser flexible y potente. Empezamos por la clase CrearTelevisorClass.php:

Observa que tenemos la propiedad $color declarada como de clase (static), al igual que los métodos encargados de leerla y escribirla. Ahora vamos a recrear la clase TelevisorOperativoClass.php, que ya conocemos, así:

Por último, creamos el archivo index.php, así:

Presta especial atención a las líneas resaltadas. Estamos invocando a métodos de clase que se declararon en CrearTelevisorClass. Sin embargo, como hay una línea de herencia, estos métodos también están disponibles en la clase derivada. Los estamos invocando como si pertenecieran a TelevisorOperativoClass, y funcionan perfectamente, como vemos en la salida en el navegador:

El color original del televisor es negro.
El nuevo color del televisor es azul.
Con el televisor apagado no se puede subir el volumen.
El televisor está encendido.
El volumen está en nivel 1.
El canal actual es 35.

Hasta aquí, todo perfecto. Ahora supongamos que hemos creado la clase CrearTelevisorClass (la clase padre), pensando en que no deba poder haber clases derivadas. Para ello, sólo tenemos que hacer un pequeño cambio en la línea 6 (la que declara la clase), que pasa de estar así:

class CrearTelevisorClass

a estar así:

final class CrearTelevisorClass

Si ahora intentamos extender esta clase en otra, como ya hemos hecho, el navegador nos hace un gran corte de mangas, así:

Fatal error: Class TelevisorOperativoClass may not inherit from final class (CrearTelevisorClass) in C:\xampp\htdocs\finalizar_clase\src\classes\TelevisorOperativoClass.php on line 102

Básicamente, nos dice que no podemos extender una clase que está declarada como final.

FINALIZANDO MÉTODOS

Hay ocasiones en que la finalización debe ser más selectiva. Podemos crear nuestra clase de modo que se puedan crear clases derivadas de la misma, pero finalizando uno o más métodos específicos, para que no puedan sobrescribirse. Sin embargo, aquí el concepto es ligeramente diferente. Cuando finalizamos un método de la clase padre, los objetos de la clase derivada lo tienen disponible. El método se hereda normalmente. Lo que no podemos hacer es sobrescribirlo en la clase derivada.

Para ver esta operativa vamos a aligerar las clases, quitándoles muchas funcionalidades, de modo que nos quedemos con lo imprescindible para entender cómo funciona esto. Observa la clase CrearTelevisorClass:

Como ves, aparte del constructor, sólo he dejado el método getPulgadas(). Ahora observa la clase derivara, TelevisorOperativoClass:

Observa que, aparte del constructor, lo hemos quitado todo, pero hemos sobrescrito el método getPulgadas(). Es el que usamos en index.php:

El objeto es de la clase derivada. Por lo tanto, cuando llamamos al método getPulgadas() de dicho objeto, no se invoca al método de la clase padre. Se invoca al método de la clase derivada (que, internamente, invoca al método de la clase padre con parent, pero eso es irrelevante. Lo que cuenta es que el método está sobrescrito).

Esto funciona como esperamos. Lo que obtenemos en el navegador es:

El televisor tiene 42 pulgadas.

Sin embargo, ahora vamos a modificar la declaración del método en la clase padre, sustituyendo la línea

public function getPulgadas()

por

final public function getPulgadas()

Cuando intentamos ejecutar, nueva peineta del navegador, así:

Fatal error: Cannot override final method CrearTelevisorClass::getPulgadas() in C:\xampp\htdocs\finalizar_metodo\src\classes\TelevisorOperativoClass.php on line 32

Nos informa de que no se puede sobrescribir un método que ha sido declarado como final en la clase padre.

Dado que el método sobrescrito en la clase derivada, hace en este ejemplo, lo mismo que su homólogo en la clase padre, podemos eliminar la sobrescritura en la clase derivada y todo vuelve a funcionar. Nos quedaría así:

En este caso, la clase derivada toma, como getPulgadas(), el método del mismo nombre que hereda de la clase padre, por lo que el objeto funciona de nuevo.

ATENCIÓN. Aunque podemos finalizar cualquier método de la clase padre, lo que, desde luego, es muy mala idea es finalizar el constructor. Este debe estar siempre disponible para ser usado en las clases derivadas.

CONCLUYENDO

Con esto damos por concluido el tema de la finalización. Los códigos de ejemplo de este artículo puedes descargarlos en este enlace. En el próximo artículo hablaremos de las interfaces y su implementación.

   

Deja un comentario