Menu
CoddyTech

Mixin vs ereditarietà

Fa parte della sezione Programmazione orientata agli oggetti del percorso Lua di Coddy. Lezione 53 di 70.

Hai imparato due modi per condividere il comportamento: l'ereditarietà crea una relazione «è un» attraverso la catena dei prototipi, mentre i mixin copiano le funzioni direttamente in una classe. Ma quando dovresti usare ciascun approccio?

Usa l’ereditarietà quando gli oggetti condividono un’identità fondamentale. Un Bird è un Animal. È sensato che Bird erediti comportamenti fondamentali degli animali, come :eat() o :sleep(). La relazione è permanente e definisce ciò che l’oggetto è fondamentalmente.

Usa i mixins quando vuoi aggiungere una funzionalità che non definisce l’identità fondamentale dell’oggetto.

Non tutti gli uccelli possono volare: i pinguini e gli struzzi sono uccelli, ma non volano. Volare è una capacità, non una caratteristica che definisce l’essere un uccello. Un mixin Flyable ti permette di aggiungere la capacità di volare agli uccelli che ne hanno bisogno, senza imporla a tutti.

I due approcci lavorano insieme. Qui sia Eagle sia Penguin ereditano da Bird, e solo Eagle riceve il mixin:

-- Bird eredita da Animal (relazione «è un»)
local Bird = {}
Bird.__index = Bird
setmetatable(Bird, {__index = Animal})

-- Eagle e Penguin sono entrambi uccelli
local Eagle = setmetatable({}, {__index = Bird})
Eagle.__index = Eagle
local Penguin = setmetatable({}, {__index = Bird})
Penguin.__index = Penguin

-- Flyable è una capacità (mixin)
local Flyable = {}
function Flyable:fly()
    print(self.name .. " soars through the sky!")
end

-- Applica il mixin solo agli uccelli che volano
applyMixin(Eagle, Flyable)

Un'aquila può chiamare :fly(). Un pinguino no: fly non è presente in Penguin, Bird o Animal, quindi penguin:fly() genera un errore. Applicare il mixin a Bird invece copierebbe fly in ogni uccello, pinguini inclusi.

challenge icon

Sfida

Facile

Costruiamo un piccolo ecosistema di creature che mostra quando usare l'ereditarietà e quando i mixin! Creerai una classe base Animal, una classe Bird che ne eredita le caratteristiche e un mixin Swimmable, perché, sebbene tutti gli uccelli siano animali, non tutti gli uccelli sanno nuotare.

Organizzerai il codice in quattro file:

  • Animal.lua: crea la classe base Animal con un costruttore :new(name) che memorizza il nome. Includi un metodo :eat() che stampa {name} is eating. Questo rappresenta l'identità fondamentale condivisa da tutti gli animali.
  • Swimmable.lua: crea un mixin con un metodo :swim() che stampa {self.name} is swimming. Si tratta di una capacità: non tutte le creature sanno nuotare, quindi non dovrebbe far parte della catena di ereditarietà.
  • Bird.lua: crea una classe Bird che eredita da Animal. Il costruttore :new(name) deve chiamare il costruttore della classe genitore. Includi un metodo :chirp() che stampa {name} chirps!. Questo è un comportamento specifico degli uccelli. Non inserire la capacità di nuotare in Bird: non tutti gli uccelli sanno nuotare.
  • main.lua: scrivi qui la funzione helper applyMixin(target, mixin): copia ogni funzione del mixin nell'oggetto target. Leggi il nome dell'uccello e se sa nuotare (yes o no). Crea un Bird e, se sa nuotare, applica il mixin Swimmable solo a quell'uccello. Poi chiama :eat() (ereditato da Animal) e :chirp() (metodo proprio di Bird), e chiama :swim() solo se questo uccello lo possiede (if bird.swim then).

Riceverai due input:

  1. Il nome dell'uccello (una stringa)
  2. Se l'uccello sa nuotare: yes o no

Se l'uccello sa nuotare, l'output dovrebbe essere:

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

Se l'uccello non sa nuotare, l'output dovrebbe essere:

{name} is eating
{name} chirps!

Per esempio, se gli input sono Duck e yes, l'output dovrebbe essere:

Duck is eating
Duck chirps!
Duck is swimming

Se gli input sono Sparrow e no, l'output dovrebbe essere:

Sparrow is eating
Sparrow chirps!

Questa sfida mostra la distinzione fondamentale: Bird è un Animal (ereditarietà), mentre nuotare è una capacità facoltativa (mixin). Poiché il mixin viene aggiunto solo agli uccelli che sanno nuotare, un uccello che non sa nuotare non ha affatto il metodo swim.

Provalo tu

-- main.lua: punto di ingresso - crea un uccello e mostra le sue capacità

-- Funzione ausiliaria per applicare un mixin a una classe o a un singolo oggetto
local function applyMixin(target, mixin)
    -- TODO: Copia tutte le funzioni da mixin a target

end

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

-- Leggi gli input
local name = io.read()
local canSwimInput = io.read()

-- TODO: Crea un'istanza di Bird con il nome

-- TODO: Se l'input è "yes", applica il mixin Swimmable solo a questo uccello

-- TODO: Chiama eat() - ereditato da Animal

-- TODO: Chiama chirp() - metodo proprio di Bird

-- TODO: Chiama swim() solo se questo uccello dispone di tale metodo
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Lua online