Mixins Simples
Parte da seção Object Oriented Programming do Journey de Lua da Coddy — lição 51 de 70.
A composição permite que você coloque objetos dentro de outros objetos. Mas e se você quiser compartilhar comportamento entre classes não relacionadas?
Um Player e um MenuItem podem ambos precisar de um método :describe(), mas eles não compartilham uma classe pai. É aqui que os mixins entram em cena.
Um mixin é simplesmente uma tabela contendo funções. Você "mistura" essas funções em uma classe copiando-as:
local Printable = {}
function Printable:describe()
print("Object: " .. tostring(self))
end
function Printable:log(message)
print("[LOG] " .. message)
endPara aplicar este mixin a uma classe, você copia cada função da tabela do mixin para a tabela da classe:
local function applyMixin(class, mixin)
for key, value in pairs(mixin) do
class[key] = value
end
end
local Player = {}
Player.__index = Player
applyMixin(Player, Printable) -- Agora Player possui :describe() e :log()Após aplicar o mixin, qualquer instância de Player pode chamar esses métodos como se estivessem definidos diretamente na classe:
local p = setmetatable({}, Player)
p:log("Player created") -- [LOG] Jogador criadoAo contrário da herança, os mixins não criam uma relação pai-filho. Você está simplesmente copiando funções de uma tabela para outra.
Isso torna os mixins perfeitos para compartilhar comportamentos utilitários — como métodos de logging, serialização ou descrição — entre classes que, de outra forma, não têm nada em comum.
Desafio
FácilVamos construir um sistema de marcação (tagging) usando mixins! Você criará um mixin Taggable que pode ser aplicado a qualquer classe, dando aos objetos a capacidade de gerenciar uma coleção de tags — útil para categorizar itens, postagens ou qualquer entidade que precise de rótulos.
Você organizará seu código em três arquivos:
Taggable.lua: Crie uma tabela mixin contendo dois métodos::addTag(tag)— adiciona uma tag aself.tags(assume que a tabela existe):listTags()— imprime todas as tags no formatoTags: tag1, tag2, tag3(ouTags: nonese estiver vazia)
Article.lua: Crie uma classe Article com um construtor:new(title)que armazena o título e inicializa uma tabelatagsvazia. Aplique o mixin Taggable para dar às instâncias de Article capacidades de marcação. Inclua um método:getTitle()que retorna o título do artigo.main.lua: Escreva a função auxiliarapplyMixinaqui (você a usará em Article.lua via require). Em seguida, leia as entradas para um título de artigo e duas tags. Crie um Article, adicione ambas as tags a ele, imprima o título e liste todas as tags.
Você receberá três entradas:
- O título do artigo (uma string)
- A primeira tag a ser adicionada (uma string)
- A segunda tag a ser adicionada (uma string)
Sua saída deve exibir o título do artigo seguido por suas tags:
Title: {title}
Tags: {tag1}, {tag2}Por exemplo, se as entradas forem Lua Basics, programming, e tutorial, a saída deve ser:
Title: Lua Basics
Tags: programming, tutorialLembre-se: os métodos do mixin funcionam porque as instâncias de Article possuem uma tabela tags na qual os métodos do mixin podem operar. O mixin não cria esta tabela — o seu construtor Article o faz. O mixin apenas fornece o comportamento compartilhado!
Folha de consulta
Um mixin é uma tabela contendo funções que podem ser compartilhadas entre classes não relacionadas sem criar uma relação pai-filho.
Para criar um mixin, defina uma tabela com métodos:
local Printable = {}
function Printable:describe()
print("Object: " .. tostring(self))
end
function Printable:log(message)
print("[LOG] " .. message)
endPara aplicar um mixin a uma classe, copie suas funções para a tabela da classe:
local function applyMixin(class, mixin)
for key, value in pairs(mixin) do
class[key] = value
end
end
local Player = {}
Player.__index = Player
applyMixin(Player, Printable)Após aplicar o mixin, as instâncias podem chamar os métodos do mixin:
local p = setmetatable({}, Player)
p:log("Player created") -- [LOG] Player createdMixins são ideais para compartilhar comportamentos utilitários como logging, serialização ou marcação entre classes que não compartilham herança.
Experimente você mesmo
-- Arquivo principal para o sistema de marcação
local Taggable = require('Taggable')
local Article = require('Article')
-- TODO: Implementar a função applyMixin
-- Esta função deve copiar todos os métodos de uma tabela mixin para uma tabela de destino
function applyMixin(target, mixin)
-- TODO: Percorrer o mixin e copiar cada método para o destino
end
-- Ler entradas
local title = io.read()
local tag1 = io.read()
local tag2 = io.read()
-- TODO: Criar um Article com o título fornecido
-- TODO: Adicionar ambas as tags ao artigo
-- TODO: Imprimir o título no formato: Title: {title}
-- TODO: Listar todas as tags usando o método listTags
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Object Oriented Programming
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ângulo2Padrã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ô