Las clases abstractas y las interfaces son herramientas que permiten definir una estructura común a las clases hijas que heredan de ellas, asegurando así una consistencia en la estructura y comportamiento de dichas clases. El polimorfismo, por otro lado, es la capacidad de los objetos de diferentes clases de responder a un mismo mensaje o llamado de método, permitiendo un mayor grado de flexibilidad en el diseño y escritura de código.
Clases abstractas, interfaces y polimorfismo
Las clases abstractas
Una clase abstracta es una clase que no puede ser instanciada directamente, sino que solo puede ser utilizada como una clase padre para crear clases hijas. La idea es que las clases hijas deben proporcionar implementaciones concretas para los métodos abstractos que se definan en la clase abstracta.
En Python, se puede utilizar la librería abc (Abstract Base Classes) para definir clases abstractas. Por ejemplo:
import abc
class ClaseAbstracta(metaclass=abc.ABCMeta):
@abc.abstractmethod
def metodo_abstracto(self):
pass
class ClaseConcreta(ClaseAbstracta):
def metodo_abstracto(self):
return "Implementación concreta del método abstracto"
En este ejemplo, la clase ClaseAbstracta es una clase abstracta y ClaseConcreta es una clase hija que proporciona una implementación concreta para el método abstracto definido en ClaseAbstracta.
Las interfaces en Python
Una interfaz en programación es un contrato o acuerdo que define un conjunto de métodos o acciones que un objeto o clase debe tener o proporcionar. Una interfaz proporciona una forma de asegurarse de que una clase cumpla con un conjunto específico de responsabilidades o comportamientos. Una clase que implementa una interfaz se compromete a proporcionar todos los métodos o acciones especificados por la interfaz. Las interfaces permiten la abstracción y la reutilización de código, ya que varias clases pueden implementar la misma interfaz.
No existen interfaces explícitas en Python, pero se pueden simular utilizando clases abstractas y verificando si un objeto implementa los métodos requeridos en tiempo de ejecución. También existen librerías como abc (Abstract Base Class) que proporcionan una forma más conveniente de crear clases abstractas y verificar la conformidad con una interfaz en Python.
Aquí hay un ejemplo de código que muestra cómo crear una interfaz en Python utilizando la librería abc (Abstract Base Class):
import abc
class Vehicle(metaclass=abc.ABCMeta):
@abc.abstractmethod
def start_engine(self):
pass
@abc.abstractmethod
def stop_engine(self):
pass
class Car(Vehicle):
def start_engine(self):
print("Car engine started")
def stop_engine(self):
print("Car engine stopped")
class Truck(Vehicle):
def start_engine(self):
print("Truck engine started")
def stop_engine(self):
print("Truck engine stopped")
car = Car()
car.start_engine() # prints "Car engine started"
car.stop_engine() # prints "Car engine stopped"
truck = Truck()
truck.start_engine() # prints "Truck engine started"
truck.stop_engine() # prints "Truck engine stopped"
En este ejemplo, la clase Vehicle es una clase abstracta que define los métodos start_engine y stop_engine que deben ser implementados por cualquier clase que herede de ella. Las clases Car y Truck son clases concretas que heredan de Vehicle y proporcionan implementaciones específicas de los métodos abstractos.
Sobre el polimorfismo
El polimorfismo es la capacidad de un objeto para tomar muchas formas, y en el contexto de la programación, significa que un objeto puede ser tratado como un objeto de diferentes tipos, dependiendo del contexto.
Hay varias formas de implementar el polimorfismo en Python, como la sobrecarga de operadores, la herencia de clases y la utilización de interfaces. Por ejemplo, en la herencia de clases, se pueden crear subclases que heredan métodos y propiedades de una clase base y también pueden proporcionar su propia implementación de esos métodos. De esta forma, una subclase puede ser tratada como un objeto de la clase base, pero también puede proporcionar su propia lógica. Por ejemplo,
Sobrecarga de operadores: se puede definir la implementación de un operador en diferentes clases, por ejemplo, el operador +, para que funcione de manera diferente en cada clase.
Métodos con el mismo nombre: diferentes clases pueden tener métodos con el mismo nombre que realizan diferentes acciones. Al invocar ese método en una instancia de una clase dada, se ejecutará la implementación correspondiente a esa clase.
En Python, la sobrecarga de operadores se logra mediante la definición de métodos especiales en la clase, como add para el operador de suma (+), len para la función len(), entre otros. Aquí hay un ejemplo de polimorfismo con la sobrecarga de operadores:
class Rectangulo:
def __init__(self, width, height):
self.width = width
self.height = height
def __repr__(self):
return f"Rectangulo({self.width}, {self.height})"
def area(self):
return self.width * self.height
class Cuadrado(Rectangulo):
def __init__(self, side):
super().__init__(side, side)
def __repr__(self):
return f"Cuadrado({self.width})"
rect = Rectangulo(2, 3)
cuad = Cuadrado(2)
print(rect.area()) # Output: 6
print(cuad.area()) # Output: 4
Aquí se puede ver que la clase Rectangulo y Cuadrado heredan de la clase Rectangulo, y aunque tienen métodos distintos, ambos pueden llamar al método area(). Este es un ejemplo de polimorfismo, ya que el método area() se comporta de manera diferente para cada clase.
El vídeo
Lo mismo que te he contando pero en formato vídeo,