Menu
Coddy logo textTech

Aplicando Múltiplos Mixins

Parte da seção Programação Orientada a Objetos do Journey de Lua da Coddy. Lição 52 de 70.

Um único mixin adiciona um conjunto de comportamentos a uma classe. Mas objetos reais geralmente precisam de recursos de várias fontes. Um objeto de jogo pode precisar se mover e ser visível na tela: duas responsabilidades distintas que não pertencem ao mesmo mixin.

A solução é simples: aplique vários mixins à mesma classe. Cada mixin contribui com seus próprios métodos, e a classe acaba com todos eles:

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

Aplique ambos os mixins à sua classe usando a mesma função 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)

Agora, as instâncias de GameObject podem tanto se mover quanto se exibir:

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

Um cuidado: se dois mixins definirem o mesmo nome de método, o segundo aplicado substituirá o primeiro. Mantenha os métodos dos mixins distintos para evitar comportamentos inesperados.

challenge icon

Desafio

Fácil

Vamos criar uma classe Character para um jogo que combina várias capacidades usando mixins! Seu personagem poderá atacar inimigos e curar a si mesmo: dois comportamentos distintos que vêm de mixins separados.

Você organizará seu código em quatro arquivos:

  • Attacker.lua: Crie um mixin com um método :attack(targetName) que imprime {self.name} attacks {targetName} for {self.damage} damage! (pressupõe que o objeto tenha os campos name e damage)
  • Healer.lua: Crie um mixin com um método :heal(amount) que adiciona o valor a self.health e imprime {self.name} heals for {amount}. Health: {newHealth}
  • Character.lua: Crie uma classe Character com um construtor :new(name, health, damage) que armazena os três atributos. Aplique os mixins Attacker e Healer para que todo personagem possa atacar e se curar. Inclua um método :status() que imprime {name} - Health: {health}, Damage: {damage}
  • main.lua: Escreva a função auxiliar applyMixin aqui. Leia as entradas para o nome, a vida e o dano de um personagem, um alvo para atacar e uma quantidade para curar. Crie um Character, mostre seu status, faça-o atacar o alvo, curar a si mesmo e, em seguida, mostre seu status novamente.

Você receberá cinco entradas:

  1. Nome do personagem (uma string)
  2. Vida inicial (um número)
  3. Valor do dano (um número)
  4. Nome do alvo a ser atacado (uma string)
  5. Quantidade a ser curada (um número)

Sua saída deve mostrar o personagem usando as duas habilidades dos mixins:

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

Por exemplo, se as entradas forem Warrior, 100, 25, Goblin e 30, a saída deverá 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 contribui com seu próprio método para a classe Character. O personagem não herda de nenhum dos mixins. Ele simplesmente adquire suas habilidades por meio da função applyMixin. Esse é o poder de combinar vários mixins!

Experimente você mesmo

-- Arquivo principal

-- TODO: Escreva a função auxiliar applyMixin
-- Esta função deve copiar todos os métodos de uma tabela mixin para uma tabela de destino
local function applyMixin(target, mixin)
    -- TODO: Implemente a aplicação do mixin
end

-- Torne applyMixin disponível globalmente para que Character.lua possa usá-lo
_G.applyMixin = applyMixin

local Character = require('Character')

-- Ler 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: Crie um Character com o name, health e damage fornecidos

-- TODO: Mostre o status do personagem

-- TODO: Faça o personagem atacar o alvo

-- TODO: Faça o personagem se curar

-- TODO: Mostre o status do personagem novamente
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Lua online