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
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Composición | un objeto contiene a otros como partes | |
| Es un | la relación de la herencia | una entrada VIP es una entrada |
| Tiene un | la relación de la composición | un coche tiene un motor |
| Delegar | pedir a una parte que haga el trabajo | |
| Acoplamiento | cuá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
| Frase | Suena bien | Se resuelve con |
|---|---|---|
| Un alumno es una persona | Sí | Herencia |
| Un alumno tiene una matrícula | Sí | Composición |
| Una factura es una lista de líneas | No | Composición: la factura tiene líneas |
| Una bicicleta eléctrica es una bicicleta | Sí | 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
# 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
mkdir -p ~/oop && cd ~/oopSe 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
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.pySe 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
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
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
| Motores | Carrocerías | Con herencia | Con composición |
|---|---|---|---|
| 2 | 2 | 4 | 4 |
| 3 | 3 | 9 | 6 |
| 4 | 4 | 16 | 8 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.