Mixins vs. Herencia
Parte de la sección Programación orientada a objetos del Journey de Lua de Coddy. Lección 53 de 70.
Has aprendido dos formas de compartir comportamiento: la herencia crea una relación «es-un» mediante la cadena de prototipos, mientras que los mixins copian funciones directamente en una clase. Pero ¿cuándo deberías usar cada enfoque?
Usa la herencia cuando los objetos comparten una identidad fundamental. Un Bird es un Animal. Tiene sentido que Bird herede comportamientos básicos de los animales, como :eat() o :sleep(). La relación es permanente y define lo que el objeto es en esencia.
Usa mixins cuando quieras añadir una capacidad que no defina la identidad central del objeto.
No todas las aves pueden volar: los pingüinos y los avestruces son aves, pero no vuelan. Volar es una capacidad, no un rasgo que defina a las aves. Un mixin Flyable te permite añadir la capacidad de volar a las aves que la necesitan, sin imponérsela a todas.
Los dos enfoques funcionan juntos. Aquí, tanto Eagle como Penguin heredan de Bird, y solo Eagle obtiene la mezcla:
-- Bird hereda de Animal (relación «es un»)
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})
-- Eagle y Penguin son aves
local Eagle = setmetatable({}, {__index = Bird})
Eagle.__index = Eagle
local Penguin = setmetatable({}, {__index = Bird})
Penguin.__index = Penguin
-- Flyable es una capacidad (mixin)
local Flyable = {}
function Flyable:fly()
print(self.name .. " soars through the sky!")
end
-- Aplica el mixin solo a las aves que vuelan
applyMixin(Eagle, Flyable)Un águila puede llamar a :fly(). Un pingüino no puede: fly no está en Penguin, Bird ni Animal, así que penguin:fly() es un error. Aplicar el mixin a Bird en su lugar copiaría fly en todas las aves, incluidos los pingüinos.
Desafío
Fácil¡Construyamos un pequeño ecosistema de criaturas que muestre cuándo usar la herencia y cuándo usar mixins! Crearás una clase base Animal, una clase Bird que hereda de ella y un mixin Swimmable, porque, aunque todos los pájaros son animales, no todos los pájaros pueden nadar.
Organizarás tu código en cuatro archivos:
Animal.lua: Crea la clase base Animal con un constructor:new(name)que almacene el nombre. Incluye un método:eat()que imprima{name} is eating. Esto representa la identidad fundamental que comparten todos los animales.Swimmable.lua: Crea un mixin con un método:swim()que imprima{self.name} is swimming. Esta es una capacidad: no todas las criaturas pueden nadar, así que no debería formar parte de la cadena de herencia.Bird.lua: Crea una clase Bird que herede de Animal. El constructor:new(name)debería llamar al constructor de la clase padre. Incluye un método:chirp()que imprima{name} chirps!. Este es un comportamiento específico de los pájaros. No incluyas la natación en Bird: no todos los pájaros pueden nadar.main.lua: Escribe aquí la función auxiliarapplyMixin(target, mixin): copia todas las funciones del mixin al objetivo. Lee el nombre del pájaro y si puede nadar (yesono). Crea un Bird y, si puede nadar, aplica el mixin Swimmable solo a ese pájaro. Luego llama a:eat()(heredado de Animal) y a:chirp()(método propio de Bird), y llama a:swim()solo si este pájaro tiene ese método (if bird.swim then).
Recibirás dos entradas:
- El nombre del pájaro (una cadena)
- Si el pájaro puede nadar:
yesono
Si el pájaro puede nadar, tu salida debería ser:
{name} is eating
{name} chirps!
{name} is swimmingSi el pájaro no puede nadar, tu salida debería ser:
{name} is eating
{name} chirps!Por ejemplo, si las entradas son Duck y yes, la salida debería ser:
Duck is eating
Duck chirps!
Duck is swimmingSi las entradas son Sparrow y no, la salida debería ser:
Sparrow is eating
Sparrow chirps!Este desafío muestra la distinción clave: Bird es un Animal (herencia), pero nadar es una capacidad opcional (mixin). Como el mixin se aplica solo a los pájaros que pueden nadar, un pájaro que no puede nadar no tiene ningún método swim.
Pruébalo tú mismo
-- main.lua: Punto de entrada: crea un pájaro y demuestra sus habilidades
-- Función auxiliar para aplicar un mixin a una clase o a un solo objeto
local function applyMixin(target, mixin)
-- TODO: Copia todas las funciones de mixin en target
end
local Bird = require('Bird')
local Swimmable = require('Swimmable')
-- Lee las entradas
local name = io.read()
local canSwimInput = io.read()
-- TODO: Crea una instancia de Bird con el nombre
-- TODO: Si la entrada es "yes", aplica el mixin Swimmable solo a este pájaro
-- TODO: Llama a eat(), heredado de Animal
-- TODO: Llama a chirp(), el método propio de Bird
-- TODO: Llama a swim() solo si este pájaro tiene ese método
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1El concepto de 'self'
Tablas con funciones'self' explícitoLa sintaxis de dos puntosPunto vs. dos puntosResumen - Punto en movimiento4Proyecto: Banco Digital
Configuración del proyectoMétodo de depósito2Patrón de prototipo de clase
El concepto de prototipoVinculación con __indexEl constructor :new()Inicialización de atributosInstancias independientesResumen - Fábrica de coches5Sobrecarga de operadores en POO
Sumar objetosRestar objetosConcatenar objetosComparar objetos (<, >)Resumen - Matemáticas de la billetera8Encapsulamiento
Convenciones de nomenclaturaClosures para privacidadAcceso mediante ClosuresTablas de solo lecturaLógica de validaciónResumen - Bóveda segura11Patrones de diseño (Lite)
Funciones FactoryTabla SingletonPatrón IteradorObserver (Listener)Resumen - Logger Factory3Estado y Comportamiento de los Objetos
Variables de InstanciaMétodos GetterMétodos SetterPropiedades CalculadasFormateo de StringsComprobaciones de IgualdadResumen - Calificación del Estudiante6Fundamentos de la herencia
Configuración de la herenciaHerencia de métodosExtender el constructorAñadir métodos hijosCompartido vs. ÚnicoResumen: Jerarquía de formas9Composición y Mixins
Relación "Tiene-Un"DelegaciónMixins simplesAplicación de múltiples MixinsMixins vs. HerenciaResumen - Ensamblaje de robotsPractica por tu cuenta: Compilador de Lua online