Applicare più mixin
Fa parte della sezione Programmazione orientata agli oggetti del percorso Lua di Coddy. Lezione 52 di 70.
Un singolo mixin aggiunge un insieme di comportamenti a una classe. Ma gli oggetti reali spesso hanno bisogno di capacità provenienti da più fonti. Un oggetto di gioco potrebbe aver bisogno di muoversi e di essere visibile sullo schermo: due aspetti distinti che non dovrebbero appartenere allo stesso mixin.
La soluzione è semplice: applica più mixin alla stessa classe. Ogni mixin aggiunge i propri metodi e la classe finisce per averli tutti:
local Movable = {}
function Movable:move(dx, dy)
self.x = self.x + dx
self.y = self.y + dy
end
local Visible = {}
function Visible:show()
print("Showing at " .. self.x .. ", " .. self.y)
end
function Visible:hide()
print("Hidden")
endApplica entrambi i mixin alla tua classe usando la stessa funzione helper di prima:
local function applyMixin(class, mixin)
for key, value in pairs(mixin) do
class[key] = value
end
end
local GameObject = {}
GameObject.__index = GameObject
applyMixin(GameObject, Movable)
applyMixin(GameObject, Visible)Ora le istanze di GameObject possono sia muoversi che visualizzarsi:
local obj = setmetatable({x = 0, y = 0}, GameObject)
obj:move(5, 3)
obj:show() -- Visualizzazione a 5, 3Una precauzione: se due mixin definiscono un metodo con lo stesso nome, il secondo applicato sovrascriverà il primo. Mantieni distinti i metodi dei tuoi mixin per evitare comportamenti imprevisti.
Sfida
FacileCostruiamo una classe Character per un gioco che combina più capacità usando i mixin! Il tuo personaggio potrà sia attaccare i nemici sia curarsi: due comportamenti distinti forniti da mixin separati.
Organizzerai il codice in quattro file:
Attacker.lua: crea un mixin con un metodo:attack(targetName)che stampa{self.name} attacks {targetName} for {self.damage} damage!(presuppone che l'oggetto abbia i campinameedamage)Healer.lua: crea un mixin con un metodo:heal(amount)che aggiunge la quantità aself.healthe stampa{self.name} heals for {amount}. Health: {newHealth}Character.lua: crea una classe Character con un costruttore:new(name, health, damage)che memorizza tutti e tre gli attributi. Applica sia il mixin Attacker sia il mixin Healer, così ogni personaggio può attaccare e curarsi. Includi un metodo:status()che stampa{name} - Health: {health}, Damage: {damage}main.lua: scrivi qui la funzione helperapplyMixin. Leggi gli input per il nome, la salute e il danno del personaggio, un bersaglio da attaccare e una quantità da curare. Crea un Character, mostra il suo stato, fagli attaccare il bersaglio e curarsi, quindi mostra di nuovo il suo stato.
Riceverai cinque input:
- Nome del personaggio (una stringa)
- Salute iniziale (un numero)
- Valore del danno (un numero)
- Nome del bersaglio da attaccare (una stringa)
- Quantità da curare (un numero)
L'output dovrebbe mostrare il personaggio mentre usa le abilità di entrambi i mixin:
{name} - Health: {health}, Damage: {damage}
{name} attacks {target} for {damage} damage!
{name} heals for {healAmount}. Health: {newHealth}
{name} - Health: {newHealth}, Damage: {damage}Per esempio, se gli input sono Warrior, 100, 25, Goblin e 30, l'output dovrebbe essere:
Warrior - Health: 100, Damage: 25
Warrior attacks Goblin for 25 damage!
Warrior heals for 30. Health: 130
Warrior - Health: 130, Damage: 25Ogni mixin fornisce il proprio metodo alla classe Character. Il personaggio non eredita da nessuno dei due mixin. Semplicemente acquisisce le loro abilità tramite la funzione applyMixin. Questa è la potenza della combinazione di più mixin!
Provalo tu
-- File principale
-- TODO: Scrivi la funzione di supporto applyMixin
-- Questa funzione deve copiare tutti i metodi da una tabella mixin a una tabella di destinazione
local function applyMixin(target, mixin)
-- TODO: Implementa l'applicazione del mixin
end
-- Rendi applyMixin disponibile globalmente affinché Character.lua possa usarla
_G.applyMixin = applyMixin
local Character = require('Character')
-- Leggi i dati in ingresso
local name = io.read()
local health = tonumber(io.read())
local damage = tonumber(io.read())
local targetName = io.read()
local healAmount = tonumber(io.read())
-- TODO: Crea un Character con il nome, la salute e il danno indicati
-- TODO: Mostra lo stato del personaggio
-- TODO: Fai attaccare il bersaglio al personaggio
-- TODO: Fai curare il personaggio
-- TODO: Mostra di nuovo lo stato del personaggio
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