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")
endAplique 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, 3Um 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.
Desafio
FácilVamos 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 camposnameedamage)Healer.lua: Crie um mixin com um método:heal(amount)que adiciona o valor aself.healthe 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 auxiliarapplyMixinaqui. 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:
- Nome do personagem (uma string)
- Vida inicial (um número)
- Valor do dano (um número)
- Nome do alvo a ser atacado (uma string)
- 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: 25Cada 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
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
1O Conceito 'Self'
Tabelas com Funções'self' ExplícitoA Sintaxe de Dois-pontosPonto vs Dois-pontosRecapitulação - Movendo o Ponto4Projeto: Banco Digital
Configuração do ProjetoMétodo de Depósito7Polimorfismo e Sobrescrita
Sobrescrita de MétodosChamando Métodos da Classe PaiDuck TypingInterface ComumVerificando o TipoRecapitulação - Papéis de Funcionários10Projeto: Gerenciador de Formas
Configuração do ProjetoClasse RetânguloClasse CírculoMétodo PerímetroColeção de FormasÁrea TotalFiltrar Formas2Padrão de Protótipo de Classe
O Conceito de ProtótipoVinculando com __indexO Construtor :new()Inicializando AtributosInstâncias IndependentesRecapitulação - Fábrica de Carros5Sobrecarga de Operadores em POO
Somando ObjetosSubtraindo ObjetosConcatenando ObjetosComparando Objetos (<, >)Recapitulação - Matemática de Carteira8Encapsulamento
Convenções de NomenclaturaClosures para PrivacidadeAcesso via ClosuresTabelas Somente LeituraLógica de ValidaçãoRecapitulação - Cofre Seguro11Padrões de Projeto (Lite)
Funções FactoryTabela SingletonPadrão IteratorObserver (Listener)Recapitulação - Logger Factory3Estado e Comportamento do Objeto
Variáveis de InstânciaMétodos GetterMétodos SetterPropriedades CalculadasFormatação de StringsVerificações de IgualdadeRecapitulação - Nota do Aluno6Fundamentos de Herança
Configurando a HerançaHerdando MétodosEstendendo o ConstrutorAdicionando Métodos FilhosCompartilhado vs ÚnicoRecapitulação - Hierarquia de Formas9Composição e Mixins
Relacionamento Tem-UmDelegaçãoMixins SimplesAplicando Múltiplos MixinsMixins vs HerançaRecapitulação - Montagem de RobôPratique por conta própria: Compilador de Lua online