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 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")
endAplica 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, 3Una 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.
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 camposnameydamage)Healer.lua: Crea un mixin con un método:heal(amount)que sume la cantidad aself.healthe 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 auxiliarapplyMixinaquí. 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:
- Nombre del personaje (una cadena)
- Salud inicial (un número)
- Valor de daño (un número)
- Nombre del objetivo a atacar (una cadena)
- 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: 25Cada 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!
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
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 robots