Menu
CoddyTech

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 muitas vezes precisam de recursos de várias fontes. Um objeto de jogo pode precisar se movimentar e ficar 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 tendo 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()  -- Exibindo 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 seus 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á tanto atacar inimigos quanto curar a si mesmo: dois comportamentos distintos que vêm de mixins separados.

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

  • Attacker.lua: Crie um mixin com um método :attack(targetName) que exibe {self.name} attacks {targetName} for {self.damage} damage! (presume que o objeto tenha os campos name e damage)
  • Healer.lua: Crie um mixin com um método :heal(amount) que adiciona a quantidade a self.health e exibe {self.name} heals for {amount}. Health: {newHealth}
  • Character.lua: Crie uma classe Character com um construtor :new(name, health, damage) que armazene os três atributos. Aplique os mixins Attacker e Healer para que cada personagem possa atacar e curar. Inclua um método :status() que exibe {name} - Health: {health}, Damage: {damage}
  • main.lua: Escreva aqui a função auxiliar applyMixin. Leia os dados de entrada para o nome, a vida e o dano de um personagem, um alvo para atacar e uma quantidade de cura. Crie um Character, mostre seu status, faça com que ataque o alvo, cure 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 para atacar (uma string)
  5. Quantidade de cura (um número)

Sua saída deve mostrar o personagem usando as habilidades de ambos os 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 de mixin para uma tabela de destino
local function applyMixin(target, mixin)
    -- TODO: Implemente a aplicação do mixin
end

-- Disponibilize applyMixin globalmente para que Character.lua possa usá-la
_G.applyMixin = applyMixin

local Character = require('Character')

-- Leia as 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 nome, a vida e o dano fornecidos

-- TODO: Mostre o status do personagem

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

-- TODO: Faça o personagem se curar

-- TODO: Mostre novamente o status do personagem
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