Mixins Simples
Parte da seção Programação orientada a objetos do Journey de Lua da Coddy. Lição 51 de 70.
A composição permite colocar objetos dentro de outros objetos. Mas e se você quiser compartilhar comportamento entre classes não relacionadas?
Um Player e um MenuItem podem precisar de um método :describe(), mas não compartilham uma classe pai. É aí que entram os mixins.
Um mixin é simplesmente uma tabela que contém funções. Você “mistura” essas funções em uma classe copiando-as para ela:
local Printable = {}
function Printable:describe()
print("Object: " .. tostring(self))
end
function Printable:log(message)
print("[LOG] " .. message)
endPara aplicar esse mixin a uma classe, copie 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 tem :describe() e :log()Depois de aplicar o mixin, qualquer instância de Player pode chamar esses métodos como se eles tivessem sido definidos diretamente na classe:
local p = setmetatable({}, Player)
p:log("Player created") -- [LOG] Player criadoDiferentemente da herança, os mixins não criam uma relação entre pai e filho. Você está simplesmente copiando funções de uma tabela para outra.
Isso torna os mixins perfeitos para compartilhar comportamentos utilitários, como registro em log, serialização ou métodos de descrição, entre classes que, de outra forma, não teriam nada em comum.
Desafio
FácilVamos criar um sistema de marcação 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, publicações ou qualquer entidade que precise de rótulos.
Você organizará seu código em três arquivos:
Taggable.lua: Crie uma tabela de mixin contendo dois métodos::addTag(tag): adiciona uma tag aself.tags(presume que a tabela exista):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. Inclua um método:getTitle()que retorna o título do artigo.main.lua: Escreva aqui a função auxiliarapplyMixine, em seguida, aplique o mixin comapplyMixin(Article, Taggable)para dar recursos de marcação às instâncias de Article. Depois, leia as entradas para o título de um artigo e duas tags. Crie um Article, adicione as duas 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 adicionar (uma string)
- A segunda tag a adicionar (uma string)
Sua saída deve exibir o título do artigo seguido pelas tags:
Title: {title}
Tags: {tag1}, {tag2}Por exemplo, se as entradas forem Lua Basics, programming e tutorial, a saída deverá ser:
Title: Lua Basics
Tags: programming, tutorialLembre-se: os métodos do mixin funcionam porque as instâncias de Article têm uma tabela tags com a qual os métodos do mixin podem operar. O mixin não cria essa tabela. Seu construtor de Article é quem a cria. O mixin apenas fornece o comportamento compartilhado!
Experimente você mesmo
-- Arquivo principal do sistema de etiquetas
local Taggable = require('Taggable')
local Article = require('Article')
-- TODO: Implemente 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: Percorra o mixin e copie cada método para target
end
-- TODO: Aplique o mixin Taggable a Article usando applyMixin
-- Leia as entradas
local title = io.read()
local tag1 = io.read()
local tag2 = io.read()
-- TODO: Crie um Article com o título fornecido
-- TODO: Adicione as duas etiquetas ao artigo
-- TODO: Imprima o título no formato: Title: {title}
-- TODO: Liste todas as etiquetas 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 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