Cómo construir una jerarquía de clases
En este apartado vamos a presentar cómo construir una jerarquía de clases. Para ello partimos de la definición de dos clases de vehículos terrestres, uno con orugas y otro con ruedas. La diferencia principal entre ellos radica en cómo realizan los giros: el vehículo con orugas lo hace deteniendo una de sus pistas, mientras que el vehículo con ruedas gira moviendo sus ruedas delanteras.
En este ejemplo inicial, las dos clases están separadas y no utilizan herencia, lo que resalta que, aunque no siempre es necesario usarla, existe la oportunidad de mejorar el diseño aprovechando este principio. Veamos el código:
import time
class VehiculoOruga:
def control_giro(self, lado, stop):
print("Pista:", lado, stop)
def girar(self, lado):
self.control_giro(lado, True)
time.sleep(0.25)
self.control_giro(lado, False)
class VehiculoRueda:
def girar_ruedas_frontales(self, lado, on):
print("Rueda:", lado, on)
def girar(self, lado):
self.girar_ruedas_frontales(lado, True)
time.sleep(0.25)
self.girar_ruedas_frontales(lado, False)
- VehiculoOruga: Esta clase representa un vehículo con orugas. Realiza el giro controlando sus pistas mediante el método
control_giro(), que detiene una de las pistas para permitir el giro. - VehiculoRueda: Esta clase representa un vehículo con ruedas, que gira moviendo sus ruedas delanteras usando el método
girar_ruedas_frontales().
Ambas clases tienen un método girar() que sigue una estructura similar para realizar el giro, lo que indica que hay duplicación de código. El método girar() en ambas clases es casi idéntico, lo cual es una clara señal de que el diseño puede ser optimizado. En lugar de repetir el mismo código en dos clases diferentes, sería más eficiente crear una superclase que encapsule el comportamiento común y dejar los detalles específicos (como la forma en que gira cada vehículo) en las subclases.
Uso de una superclase
Para mejorar la estructura, se propone la introducción de una superclase que contenga el método girar(), centralizando la lógica común. Las subclases se encargarían de implementar los detalles específicos, como el control de las pistas o el movimiento de las ruedas delanteras.
import time
class Vehiculo:
def cambia_direccion(lado, on):
pass
def girar(self,lado):
self.cambia_direccion(lado, True)
time.sleep(0.25)
self.cambia_direccion(lado, False)
class VehiculoOruga(Vehiculo):
def control_giro(self, lado, stop):
print("Pista:", lado, stop)
def cambia_direccion(self, lado, on):
self.control_giro(lado, on)
class VehiculoRueda(Vehiculo):
def girar_ruedas_frontales(self, lado, on):
print("Rueda:", lado, on)
def cambia_direccion(self, lado, on):
self.girar_ruedas_frontales(lado, on)
- Definimos una superclase llamada
Vehiculo, la cual utiliza el métodogirar()para implementar un esquema para poder girar, mientras que el giro en si es realizado porcambia_direccion(); nota: dicho método está vacío, ya que vamos a poner todos los detalles en la subclase (dicho método a menudo se denomina método abstracto, ya que solo demuestra alguna posibilidad que será instanciada más tarde). - Definimos una subclase llamada
VehiculoOruga(nota: es derivada de la claseVehiculo) la cual instancia el métodocambia_direccion()utilizando el método denominadocontrol_giro(). - De manera similar, la subclase llamada
VehiculoRuedahace lo mismo, pero usa el métodogirar_ruedas_frontales()para obligar al vehículo a girar.
La ventaja más importante es que esta forma de código te permite implementar un nuevo algoritmo de giro simplemente modificando el método girar(), lo cual se puede hacer en un solo lugar, ya que todos los vehículos lo obedecerán.
Así es como el el poliformismo ayuda al desarrollador a mantener el código limpio y consistente.