¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Composición frente a herencia

Después de esta lección: Puedo elegir composición en lugar de herencia y explicar por qué.

Lección de 65 min4 comandosLaboratorio de comandos de Linux de cada día: los treinta comandos que se escriben de memoria

Un coche tiene un motor, no lo es

La composición construye un objeto a partir de otros objetos que hacen de partes. Permite cambiar una parte sin tocar el resto, y por eso suele ser mejor opción que la herencia.

Una empresa de alquiler tiene coches de gasolina y eléctricos. Con herencia acabaría con una clase por cada combinación. Con composición, un coche recibe el motor que lleva.

Al final de esta lección

Nota

Puedo elegir composición en lugar de herencia y explicar por qué.

Palabras clave

PalabraQué significaEjemplo
Composiciónun objeto contiene a otros como partes
Es unla relación de la herenciauna entrada VIP es una entrada
Tiene unla relación de la composiciónun coche tiene un motor
Delegarpedir a una parte que haga el trabajo
Acoplamientocuánto depende una clase de otra

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Herencia para «es un», composición para «tiene un»

Antes de escribir una clase, di la frase en voz alta. «Una entrada VIP es una entrada» suena bien: es herencia. «Un coche es un motor» suena mal.

«Un coche tiene un motor» suena bien: es composición. El motor pasa a ser un atributo del coche.

Ejemplo: cuál es la relación

FraseSuena bienSe resuelve con
Un alumno es una personaSíHerencia
Un alumno tiene una matrículaSíComposición
Una factura es una lista de líneasNoComposición: la factura tiene líneas
Una bicicleta eléctrica es una bicicletaSíHerencia

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

El coche delega el trabajo en su motor

En la composición, el objeto grande no hace el trabajo de la parte. Se lo delega. Coche.coste_viaje solo llama a self.motor.coste(km).

Cualquier objeto con un método coste sirve como motor. El coche no necesita saber de qué clase es.

Un coche que delega y cambia de motor

Código: python
# Un coche tiene un motor. Los costes van en céntimos.
class MotorGasolina:
    def coste(self, km):
        return km * 12

class MotorElectrico:
    def coste(self, km):
        return km * 4

class Coche:
    def __init__(self, motor):
        self.motor = motor

    def coste_viaje(self, km):
        # El coche no calcula nada: se lo pide a su motor.
        return self.motor.coste(km)

coche = Coche(MotorGasolina())
print(coche.coste_viaje(100))
coche.motor = MotorElectrico()
print(coche.coste_viaje(100))
# Añade una clase MotorDiesel que cueste 9 céntimos por km y pruébala.

Prueba el cambio de motor en el laboratorio

Guarda las clases en motores.py y úsalas desde la terminal. El importe sale en céntimos: 1200 céntimos son 12 euros.

Predice el segundo resultado antes de pulsar Ejecutar. Solo cambia la parte, no el coche.

Entra en la carpeta de trabajo

Comando
mkdir -p ~/oop && cd ~/oop

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Escribe los motores y el coche

Comando
printf 'class MotorGasolina:\n    def coste(self, km):\n        return km * 12\n\n\nclass MotorElectrico:\n    def coste(self, km):\n        return km * 4\n\n\nclass Coche:\n    def __init__(self, motor):\n        self.motor = motor\n\n    def coste_viaje(self, km):\n        return self.motor.coste(km)\n' > motores.py

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Cambia el motor y pide el coste

Comando
python3 -c "from motores import Coche, MotorGasolina, MotorElectrico; c = Coche(MotorGasolina()); print(c.coste_viaje(100)); c.motor = MotorElectrico(); print(c.coste_viaje(100))"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Comprueba que el coche no es un motor

Comando
python3 -c "from motores import Coche, MotorGasolina; c = Coche(MotorGasolina()); print(isinstance(c, MotorGasolina), isinstance(c.motor, MotorGasolina))"

Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.

Un error frecuente

Advertencia

Mucha gente cree que la herencia es mejor porque se escribe menos. Con pocas clases es verdad. Pero cada combinación nueva obliga a otra clase. Con composición, las partes son clases pequeñas que se combinan y se prueban por separado.

La herencia crea una clase por combinación

Imagina que el cliente elige un motor y una carrocería. Con herencia necesitas una clase por cada pareja. Con composición, una clase por motor y otra por carrocería.

La tabla compara cuántas clases hacen falta. Con cuatro motores y cuatro carrocerías, la herencia ya pide el doble.

Ejemplo: cuántas clases hacen falta

MotoresCarroceríasCon herenciaCon composición
2244
3396
44168

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Sobre este laboratorio y su código: Laboratorio de comandos de Linux de cada día: los treinta comandos que se escriben de memoria

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.