Menu
Coddy logo textTech

Mixins simples

Parte de la sección Object Oriented Programming del Journey de Lua de Coddy — lección 51 de 70.

La composición te permite poner objetos dentro de otros objetos. Pero, ¿qué pasa si quieres compartir comportamiento entre clases no relacionadas?

Un Player y un MenuItem podrían necesitar ambos un método :describe(), pero no comparten una clase padre. Aquí es donde entran los mixins.

Un mixin es simplemente una tabla que contiene funciones. Puedes "mezclar" estas funciones en una clase copiándolas:

local Printable = {}

function Printable:describe()
    print("Object: " .. tostring(self))
end

function Printable:log(message)
    print("[LOG] " .. message)
end

Para aplicar este mixin a una clase, se copia cada función de la tabla del mixin a la tabla de la clase:

local function applyMixin(class, mixin)
    for key, value in pairs(mixin) do
        class[key] = value
    end
end

local Player = {}
Player.__index = Player

applyMixin(Player, Printable)  -- Ahora Player tiene :describe() y :log()

Después de aplicar el mixin, cualquier instancia de Player puede llamar a esos métodos como si estuvieran definidos directamente en la clase:

local p = setmetatable({}, Player)
p:log("Player created")  -- [LOG] Jugador creado

A diferencia de la herencia, los mixins no crean una relación padre-hijo. Simplemente estás copiando funciones de una tabla a otra.

Esto hace que los mixins sean perfectos para compartir comportamientos de utilidad —como el registro (logging), la serialización o los métodos de descripción— entre clases que, de otro modo, no tienen nada en común.

challenge icon

Desafío

Fácil

¡Vamos a construir un sistema de etiquetas usando mixins! Crearás un mixin Taggable que se puede aplicar a cualquier clase, otorgando a los objetos la capacidad de gestionar una colección de etiquetas, lo cual es útil para categorizar elementos, publicaciones o cualquier entidad que necesite etiquetas.

Organizarás tu código en tres archivos:

  • Taggable.lua: Crea una tabla mixin que contenga dos métodos:
    • :addTag(tag) — añade una etiqueta a self.tags (asume que la tabla existe)
    • :listTags() — imprime todas las etiquetas en el formato Tags: tag1, tag2, tag3 (o Tags: none si está vacía)
  • Article.lua: Crea una clase Article con un constructor :new(title) que almacene el título e inicialice una tabla tags vacía. Aplica el mixin Taggable para dar a las instancias de Article capacidades de etiquetado. Incluye un método :getTitle() que devuelva el título del artículo.
  • main.lua: Escribe la función auxiliar applyMixin aquí (la usarás en Article.lua a través de require). Luego lee las entradas para el título de un artículo y dos etiquetas. Crea un Article, añádele ambas etiquetas, imprime el título y enumera todas las etiquetas.

Recibirás tres entradas:

  1. El título del artículo (una cadena)
  2. La primera etiqueta a añadir (una cadena)
  3. La segunda etiqueta a añadir (una cadena)

Tu salida debe mostrar el título del artículo seguido de sus etiquetas:

Title: {title}
Tags: {tag1}, {tag2}

Por ejemplo, si las entradas son Lua Basics, programming, y tutorial, la salida debería ser:

Title: Lua Basics
Tags: programming, tutorial

Recuerda: los métodos del mixin funcionan porque las instancias de Article tienen una tabla tags sobre la cual los métodos del mixin pueden operar. El mixin no crea esta tabla; tu constructor de Article lo hace. ¡El mixin solo proporciona el comportamiento compartido!

Hoja de referencia

Un mixin es una tabla que contiene funciones que pueden compartirse entre clases no relacionadas sin crear una relación padre-hijo.

Para crear un mixin, define una tabla con métodos:

local Printable = {}

function Printable:describe()
    print("Object: " .. tostring(self))
end

function Printable:log(message)
    print("[LOG] " .. message)
end

Para aplicar un mixin a una clase, copia sus funciones en la tabla de la clase:

local function applyMixin(class, mixin)
    for key, value in pairs(mixin) do
        class[key] = value
    end
end

local Player = {}
Player.__index = Player

applyMixin(Player, Printable)

Después de aplicar el mixin, las instancias pueden llamar a los métodos del mixin:

local p = setmetatable({}, Player)
p:log("Player created")  -- [LOG] Player created

Los mixins son ideales para compartir comportamientos de utilidad como el registro (logging), la serialización o el etiquetado entre clases que no comparten herencia.

Pruébalo tú mismo

-- Archivo principal para el sistema de etiquetado
local Taggable = require('Taggable')
local Article = require('Article')

-- TODO: Implementar la función applyMixin
-- Esta función debe copiar todos los métodos de una tabla mixin a una tabla de destino
function applyMixin(target, mixin)
    -- TODO: Recorrer el mixin y copiar cada método al destino
end

-- Leer entradas
local title = io.read()
local tag1 = io.read()
local tag2 = io.read()

-- TODO: Crear un Artículo con el título dado

-- TODO: Añadir ambas etiquetas al artículo

-- TODO: Imprimir el título en formato: Title: {title}

-- TODO: Listar todas las etiquetas usando el método listTags
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 Object Oriented Programming