Menu
CoddyTech

Aplicación de múltiples Mixins

Parte de la sección Programación orientada a objetos del Journey de Lua de Coddy. Lección 52 de 70.

Un mixin añade un conjunto de comportamientos a una clase. Pero los objetos reales a menudo necesitan capacidades de varias fuentes. Un objeto del juego podría necesitar moverse y ser visible en pantalla: dos aspectos distintos que no pertenecen al mismo mixin.

La solución es sencilla: aplica varios mixins a la misma clase. Cada mixin aporta sus propios métodos, y la clase termina con 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 que 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:

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

Una precaución: si dos mixins definen un método con el mismo nombre, el segundo que se aplique sobrescribirá al primero. Mantén distintos los métodos de tus mixins para evitar comportamientos inesperados.

challenge icon

Desafío

Fácil

¡Creemos una clase Character para un juego que combine varias capacidades mediante mixins! Tu personaje podrá tanto atacar a los enemigos como curarse: dos comportamientos distintos que provienen de mixins separados.

Organizarás el 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! (supone 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 los mixins Attacker y Healer para que cada personaje pueda atacar y curarse. Incluye un método :status() que imprima {name} - Health: {health}, Damage: {damage}
  • main.lua: Escribe aquí la función auxiliar applyMixin. Lee los datos de entrada para el nombre, la salud y el daño de un personaje, un objetivo al que atacar y una cantidad para curarse. Crea un Character, muestra su estado, haz que ataque al objetivo, que se cure y, después, vuelve a mostrar su estado.

Recibirás cinco datos de entrada:

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

Tu salida debe mostrar al personaje usando las habilidades de ambos mixins:

{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 los datos de entrada 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 dos mixins. Simplemente obtiene sus habilidades mediante la función applyMixin. ¡Este es el poder de combinar varios mixins!

Pruébalo tú mismo

-- Archivo principal

-- TODO: Escribe 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: Implementa la aplicación del mixin
end

-- Haz que applyMixin esté disponible globalmente para que Character.lua pueda usarla
_G.applyMixin = applyMixin

local Character = require('Character')

-- Lee las 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: Crea un Character con el nombre, la salud y el daño indicados

-- TODO: Muestra el estado del personaje

-- TODO: Haz que el personaje ataque al objetivo

-- TODO: Haz que el personaje se cure

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