Menu
Coddy logo textTech

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 de «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 compartan una identidad fundamental. Un Bird es un Animal. Tiene sentido que Bird herede comportamientos animales básicos como :eat() o :sleep(). La relación es permanente y define lo que el objeto es fundamentalmente.

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 definitorio de ser un ave. 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 perfectamente juntos:

-- Bird hereda de Animal (relación is-a)
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})

-- 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 pueden volar
applyMixin(Bird, Flyable)

Este patrón te ofrece lo mejor de ambos mundos: una jerarquía de clases clara para una identidad compartida, además de capacidades flexibles que se pueden incorporar donde sea necesario.

challenge icon

Desafío

Fácil

¡Construyamos un pequeño ecosistema de criaturas que demuestre cuándo usar la herencia y cuándo usar mixins! Crearás una clase base Animal, un Bird que hereda de ella y un mixin Swimmable, porque, aunque todas las aves son animales, no todas las aves 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, canSwim) debe llamar al constructor principal y almacenar si esta ave puede nadar. Aplica el mixin Swimmable a la clase Bird. Incluye un método :chirp() que imprima {name} chirps!. Este es un comportamiento específico de las aves.
  • main.lua: Escribe aquí la función auxiliar applyMixin. Lee los datos de entrada correspondientes al nombre de un ave y a si puede nadar (yes o no). Crea una instancia de Bird y después demuestra sus capacidades: llama a :eat() (heredado de Animal), llama a :chirp() (método propio de Bird) y llama a :swim() solo si el ave puede nadar.

Recibirás dos datos de entrada:

  1. El nombre del ave (una cadena)
  2. Si el ave puede nadar: yes o no

Si el ave puede nadar, tu salida debería ser:

{name} is eating
{name} chirps!
{name} is swimming

Si el ave 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 swimming

Si 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). El mixin se aplica a la clase, pero tu lógica principal decide si usarlo según las capacidades del ave individual.

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
local function applyMixin(class, mixin)
    -- TODO: Copia todos los métodos del mixin a la clase
    
end

-- Aplica el mixin Swimmable a Bird antes de requerir Bird
-- Note: Puede que necesites manejar esto en Bird.lua o aquí

local Bird = require('Bird')
local Swimmable = require('Swimmable')

-- Aplica el mixin a la clase Bird
applyMixin(Bird, Swimmable)

-- Lee las entradas
local name = io.read()
local canSwimInput = io.read()

-- TODO: Determina si el pájaro puede nadar basándote en la entrada ("yes" o "no")

-- TODO: Crea una instancia de Bird con el nombre y la capacidad de nadar

-- TODO: Llama a eat() - heredado de Animal

-- TODO: Llama a chirp() - método propio de Bird

-- TODO: Solo llama a swim() si el pájaro puede nadar
quiz iconPonte a prueba

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

Practica por tu cuenta: Compilador de Lua online