Menu
Coddy logo textTech

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)
end

Para 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 criado

Ao 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.

challenge icon

Desafio

Fácil

Vamos 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 a self.tags (assume que a tabela existe)
    • :listTags() — imprime todas as tags no formato Tags: tag1, tag2, tag3 (ou Tags: none se estiver vazia)
  • Article.lua: Crie uma classe Article com um construtor :new(title) que armazena o título e inicializa uma tabela tags vazia. 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 auxiliar applyMixin aqui (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:

  1. O título do artigo (uma string)
  2. A primeira tag a ser adicionada (uma string)
  3. 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, tutorial

Lembre-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)
end

Para 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 created

Mixins 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
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 Object Oriented Programming