Menu
Coddy logo textTech

Mixins vs Herança

Parte da seção Programação Orientada a Objetos do Journey de Lua da Coddy. Lição 53 de 70.

Você aprendeu duas maneiras de compartilhar comportamento: a herança cria uma relação de "é-um" por meio da cadeia de protótipos, enquanto os mixins copiam funções diretamente para uma classe. Mas quando você deve usar cada abordagem?

Use herança quando os objetos compartilham uma identidade fundamental. Um Bird é um Animal. Faz sentido que Bird herde comportamentos fundamentais de animais, como :eat() ou :sleep(). O relacionamento é permanente e define o que o objeto é fundamentalmente.

Use mixins quando quiser adicionar uma capacidade que não define a identidade central do objeto.

Nem todas as aves podem voar: pinguins e avestruzes são aves, mas não voam. Voar é uma capacidade, não uma característica definidora de ser uma ave. Um mixin Flyable permite adicionar voo às aves que precisam disso, sem impô-lo a todas elas.

As duas abordagens funcionam muito bem juntas:

-- Bird herda de Animal (relacionamento is-a)
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})

-- Flyable é uma capacidade (mixin)
local Flyable = {}
function Flyable:fly()
    print(self.name .. " soars through the sky!")
end

-- Aplique o mixin apenas a pássaros que podem voar
applyMixin(Bird, Flyable)

Esse padrão oferece o melhor dos dois mundos: uma hierarquia de classes clara para uma identidade compartilhada, além de capacidades flexíveis que podem ser combinadas quando necessário.

challenge icon

Desafio

Fácil

Vamos criar um pequeno ecossistema de criaturas que demonstra quando usar herança em vez de mixins! Você criará uma classe base Animal, uma classe Bird que herda dela e um mixin Swimmable, pois, embora todas as aves sejam animais, nem todas as aves sabem nadar.

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

  • Animal.lua: crie a classe base Animal com um construtor :new(name) que armazena o nome. Inclua um método :eat() que imprime {name} is eating. Isso representa a identidade central compartilhada por todos os animais.
  • Swimmable.lua: crie um mixin com um método :swim() que imprime {self.name} is swimming. Essa é uma capacidade; nem todas as criaturas sabem nadar, portanto ela não deve fazer parte da cadeia de herança.
  • Bird.lua: crie uma classe Bird que herda de Animal. O construtor :new(name, canSwim) deve chamar o construtor da classe pai e armazenar se essa ave sabe nadar. Aplique o mixin Swimmable à classe Bird. Inclua um método :chirp() que imprime {name} chirps!. Esse é um comportamento específico de aves.
  • main.lua: escreva aqui a função auxiliar applyMixin. Leia as entradas para o nome da ave e se ela sabe nadar (yes ou no). Crie uma instância de Bird e, em seguida, demonstre suas habilidades: chame :eat() (herdado de Animal), chame :chirp() (método próprio de Bird) e chame :swim() somente se a ave souber nadar.

Você receberá duas entradas:

  1. O nome da ave (uma string)
  2. Se a ave sabe nadar: yes ou no

Se a ave souber nadar, sua saída deverá ser:

{name} is eating
{name} chirps!
{name} is swimming

Se a ave não souber nadar, sua saída deverá ser:

{name} is eating
{name} chirps!

Por exemplo, se as entradas forem Duck e yes, a saída deverá ser:

Duck is eating
Duck chirps!
Duck is swimming

Se as entradas forem Sparrow e no, a saída deverá ser:

Sparrow is eating
Sparrow chirps!

Este desafio mostra a distinção fundamental: Bird é um Animal (herança), mas nadar é uma capacidade opcional (mixin). O mixin é aplicado à classe, mas sua lógica principal decide se deve usá-lo com base nas habilidades de cada ave!

Experimente você mesmo

-- main.lua: Ponto de entrada - cria um pássaro e demonstra suas habilidades

-- Função auxiliar para aplicar um mixin a uma classe
local function applyMixin(class, mixin)
    -- TODO: Copie todos os métodos do mixin para a classe
    
end

-- Aplique o mixin Swimmable a Bird antes de fazer o require de Bird
-- Note: Você pode precisar lidar com isso em Bird.lua ou aqui

local Bird = require('Bird')
local Swimmable = require('Swimmable')

-- Aplique o mixin à classe Bird
applyMixin(Bird, Swimmable)

-- Lê as entradas
local name = io.read()
local canSwimInput = io.read()

-- TODO: Determine se o pássaro pode nadar com base na entrada ("yes" ou "no")

-- TODO: Crie uma instância de Bird com o nome e a habilidade de nadar

-- TODO: Chame eat() - herdado de Animal

-- TODO: Chame chirp() - método próprio de Bird

-- TODO: Chame swim() apenas se o pássaro puder nadar
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