Menu
Coddy logo textTech

Aplicación de múltiples Mixins

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

Un solo mixin añade un conjunto de comportamientos a una clase. Pero los objetos reales a menudo necesitan capacidades de múltiples fuentes. Un objeto de juego podría necesitar moverse y ser visible en pantalla—dos preocupaciones separadas que no pertenecen al mismo mixin.

La solución es sencilla: aplica múltiples mixins a la misma clase. Cada mixin aporta sus propios métodos, y la clase termina teniendo todos ellos:

local Movable = {}
function Movable:move(dx, dy)
    self.x = self.x + dx
    self.y = self.y + dy
end

local Visible = {}
function Visible:show()
    print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
    print("Hidden")
end

Aplica ambos mixins a tu clase usando la misma función auxiliar de antes:

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

local GameObject = {}
GameObject.__index = GameObject

applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)

Ahora las instancias de GameObject pueden tanto moverse como mostrarse a sí mismas:

local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show()  -- Mostrando en 5, 3

Una advertencia: si dos mixins definen el mismo nombre de método, el segundo aplicado sobrescribirá al primero. Mantén tus métodos de mixin distintos para evitar comportamientos inesperados.

challenge icon

Desafío

Fácil

¡Vamos a construir una clase Character para un juego que combina múltiples capacidades usando mixins! Tu personaje podrá tanto atacar enemigos como curarse a sí mismo—dos comportamientos distintos que provienen de mixins separados.

Organizarás tu código en cuatro archivos:

  • Attacker.lua: Crea un mixin con un método :attack(targetName) que imprima {self.name} attacks {targetName} for {self.damage} damage! (asume que el objeto tiene los campos name y damage)
  • Healer.lua: Crea un mixin con un método :heal(amount) que sume la cantidad a self.health e imprima {self.name} heals for {amount}. Health: {newHealth}
  • Character.lua: Crea una clase Character con un constructor :new(name, health, damage) que almacene los tres atributos. Aplica tanto el mixin Attacker como el Healer para que cada personaje pueda atacar y curar. Incluye un método :status() que imprima {name} - Health: {health}, Damage: {damage}
  • main.lua: Escribe la función auxiliar applyMixin aquí. Lee las entradas para el nombre de un personaje, salud, daño, un objetivo para atacar y una cantidad de curación. Crea un Character, muestra su estado, haz que ataque al objetivo, se cure a sí mismo y luego muestra su estado nuevamente.

Recibirás cinco entradas:

  1. Nombre del personaje (una cadena)
  2. Salud inicial (un número)
  3. Valor de daño (un número)
  4. Nombre del objetivo a atacar (una cadena)
  5. Cantidad a curar (un número)

Tu salida debe mostrar al personaje usando ambas habilidades del mixin:

{name} - Health: {health}, Damage: {damage}
{name} attacks {target} for {damage} damage!
{name} heals for {healAmount}. Health: {newHealth}
{name} - Health: {newHealth}, Damage: {damage}

Por ejemplo, si las entradas son Warrior, 100, 25, Goblin y 30, la salida debería ser:

Warrior - Health: 100, Damage: 25
Warrior attacks Goblin for 25 damage!
Warrior heals for 30. Health: 130
Warrior - Health: 130, Damage: 25

Cada mixin aporta su propio método a la clase Character. El personaje no hereda de ninguno de los mixins—simplemente adquiere sus habilidades a través de la función applyMixin. ¡Este es el poder de combinar múltiples mixins!

Hoja de referencia

Se pueden aplicar múltiples mixins a una sola clase para combinar diferentes conjuntos de comportamientos. Cada mixin aporta sus propios métodos a la clase.

Define mixins separados para diferentes propósitos:

local Movable = {}
function Movable:move(dx, dy)
    self.x = self.x + dx
    self.y = self.y + dy
end

local Visible = {}
function Visible:show()
    print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
    print("Hidden")
end

Aplica múltiples mixins a una clase utilizando la función auxiliar applyMixin:

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

local GameObject = {}
GameObject.__index = GameObject

applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)

La clase ahora tiene métodos de todos los mixins aplicados:

local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show()  -- Showing at 5, 3

Importante: Si dos mixins definen el mismo nombre de método, el segundo mixin aplicado sobrescribirá al primero. Mantén los nombres de los métodos distintos entre los mixins para evitar conflictos.

Pruébalo tú mismo

-- Archivo principal

-- TODO: Escribir la función auxiliar applyMixin
-- Esta función debe copiar todos los métodos de una tabla mixin a una tabla de destino
local function applyMixin(target, mixin)
    -- TODO: Implementar la aplicación del mixin
end

-- Hacer que applyMixin esté disponible globalmente para que Character.lua pueda usarlo
_G.applyMixin = applyMixin

local Character = require('Character')

-- Leer entradas
local name = io.read()
local health = tonumber(io.read())
local damage = tonumber(io.read())
local targetName = io.read()
local healAmount = tonumber(io.read())

-- TODO: Crear un Character con el nombre, salud y daño dados

-- TODO: Mostrar el estado del personaje

-- TODO: Hacer que el personaje ataque al objetivo

-- TODO: Hacer que el personaje se cure a sí mismo

-- TODO: Mostrar el estado del personaje de nuevo
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