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.
Sfida
FacileCostruiamo 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 helperapplyMixin(target, mixin): copia ogni funzione del mixin nell'oggetto target. Leggi il nome dell'uccello e se sa nuotare (yesono). 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:
- Il nome dell'uccello (una stringa)
- Se l'uccello sa nuotare:
yesono
Se l'uccello sa nuotare, l'output dovrebbe essere:
{name} is eating
{name} chirps!
{name} is swimmingSe 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 swimmingSe 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
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
1Il concetto di «self»
Tabelle con funzioni«self» esplicitoLa sintassi dei due puntiPunto o due puntiRiepilogo - Spostare il punto4Progetto: Banca digitale
Configurazione del progettoMetodo di deposito2Schema del prototipo di classe
Il concetto di prototipoCollegare con __indexIl costruttore :new()Inizializzare gli attributiIstanze indipendentiRiepilogo - Fabbrica di auto5Sovraccarico degli operatori nella OOP
Sommare oggettiSottrarre oggettiConcatenare oggettiConfrontare oggetti (<, >)Ripasso - Calcoli con il portafoglio8Incapsulamento
Convenzioni di denominazioneClosure per la privacyAccesso tramite closureTabelle di sola letturaLogica di convalidaRiepilogo - Cassaforte sicura11Modelli di progettazione (base)
Funzioni factoryTabella singletonPattern IteratorObserver (listener)Riepilogo - Factory per logger3Stato e comportamento degli oggetti
Variabili di istanzaMetodi getterMetodi setterProprietà calcolateFormattazione delle stringheControlli di uguaglianzaRiepilogo - Voto dello studente6Fondamenti dell'ereditarietà
Configurare l'ereditarietàEreditare i metodiEstendere il costruttoreAggiungere metodi alla classe figliaCondiviso vs specificoRiepilogo - Gerarchia delle forme9Composizione e mixin
Relazione Has-ADelegaMixin sempliciApplicare più mixinMixin vs ereditarietàRiepilogo - Assemblaggio di robotEsercitati da solo: Compilatore Lua online