Override e polimorfismo
Esegua l'override dei metodi ereditati e ottenga il dispatch polimorfico a runtime.
Override e polimorfismo è una lezione Lua Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Lua Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Lua Academy include 4 lezioni in totale.
Sovrascrittura dei metodi
Una classe figlia sovrascrive un metodo della classe padre definendo un metodo con lo stesso nome. Quando viene chiamato su un'istanza figlia, viene eseguita la versione della figlia. La versione del padre resta accessibile tramite Parent.method(self).
local Shape={} Shape.__index=Shape
function Shape:area() return 0 end
function Shape:describe() print(type(self).." area="..self:area()) end
local Circle={} Circle.__index=Circle
setmetatable(Circle,{__index=Shape})
function Circle.new(r) return setmetatable({r=r},Circle) end
function Circle:area() return math.pi*self.r^2 end
local Square={} Square.__index=Square
setmetatable(Square,{__index=Shape})
function Square.new(s) return setmetatable({s=s},Square) end
function Square:area() return self.s^2 end
Circle.new(5):describe()
Square.new(4):describe()Dispatch polimorfico
Il polimorfismo consente a oggetti di tipo diverso di rispondere in modo diverso allo stesso messaggio. Una funzione che accetta qualsiasi "forma" e chiama :area() funziona con ogni tipo di forma: ciascuno risponde con la propria implementazione.
local shapes={
Circle.new(3),
Square.new(4),
Circle.new(1),
}
local total=0
for _,shape in ipairs(shapes) do
total=total+shape:area()
end
print(string.format("Total area: %.2f",total))Duck typing
Lua utilizza il duck typing: se un oggetto possiede il metodo, può essere utilizzato. Non è necessaria alcuna dichiarazione formale dell'interfaccia. Una funzione che chiama :speak() funziona con qualsiasi oggetto che disponga di un metodo speak, indipendentemente dalla classe.
local function makeNoise(obj)
if type(obj.speak)=="function" then
obj:speak()
else
print("(silent)")
end
end
local Duck={speak=function(self) print("Quack!") end}
local Robot={speak=function(self) print("Beep boop!") end}
local Rock={}
makeNoise(Duck) -- Quack!
makeNoise(Robot) -- Beep boop!
makeNoise(Rock) -- (silent)Polimorfismo degli operatori
I metametodi come __add abilitano il polimorfismo degli operatori. Tipi diversi possono rispondere a + con una propria semantica, purché definiscano __add.
local Vec2={} Vec2.__index=Vec2
Vec2.__add=function(a,b) return Vec2.new(a.x+b.x,a.y+b.y) end
Vec2.__tostring=function(v) return "("..v.x..","..v.y..")" end
function Vec2.new(x,y) return setmetatable({x=x,y=y},Vec2) end
local Color={} Color.__index=Color
Color.__add=function(a,b)
return Color.new(math.min(255,a.r+b.r),math.min(255,a.g+b.g),math.min(255,a.b+b.b))
end
function Color.new(r,g,b) return setmetatable({r=r,g=g,b=b},Color) end
print(tostring(Vec2.new(1,2)+Vec2.new(3,4))) -- (4,6)Visitor pattern
Il visitor pattern separa le operazioni dagli oggetti. Un'operazione "visita" oggetti di tipo diverso e chiama il metodo appropriato in base al tipo. Lo utilizzi per operazioni che devono variare a seconda del tipo senza modificare i tipi stessi.
local function printInfo(obj)
local mt = getmetatable(obj)
if mt == Circle then
print(string.format("Circle r=%.1f area=%.2f",obj.r,obj:area()))
elseif mt == Square then
print(string.format("Square s=%.1f area=%.2f",obj.s,obj:area()))
end
end
for _,s in ipairs({Circle.new(3),Square.new(4)}) do
printInfo(s)
endTabella dell'interfaccia
Definisca un'interfaccia come una tabella di nomi di metodi. Verifichi che un oggetto implementi tutti i metodi richiesti prima di utilizzarlo in modo polimorfico.
local function implements(obj, interface)
for _, method in ipairs(interface) do
if type(obj[method]) ~= "function" then
return false, "missing: "..method
end
end
return true
end
local Drawable = {"draw","resize","move"}
local Widget = {
draw=function(self) print("draw "..self.type) end,
resize=function(self,w,h) self.w,self.h=w,h end,
move=function(self,x,y) self.x,self.y=x,y end,
type="button"
}
local ok,err = implements(Widget,Drawable)
print(ok,err) -- true nilVerifica dell'esistenza di un metodo
Prima di chiamare polimorficamente un metodo opzionale, verifichi che l'oggetto lo possieda. In questo modo è possibile offrire capacità opzionali senza richiedere una classe base comune.
local function maybeUpdate(obj, dt)
if type(obj.update)=="function" then
obj:update(dt)
end
end
local objects={
{x=0,y=0,update=function(self,dt) self.x=self.x+10*dt end},
{x=0,y=0}, -- no update
{x=0,y=0,update=function(self,dt) self.y=self.y+5*dt end},
}
for _,o in ipairs(objects) do maybeUpdate(o,1) end
for _,o in ipairs(objects) do print(o.x,o.y) endTabella di dispatch basata sul tipo
Anziché usare catene di if/elseif, utilizzi una tabella di dispatch: associ i nomi dei tipi alle funzioni gestore. Questo è lo schema del polimorfismo guidato da tabella.
local handlers={
number = function(v) return "num:"..v end,
string = function(v) return "str:\"".."..v.."\"" end,
boolean = function(v) return "bool:"..(v and "T" or "F") end,
table = function(v) return "tbl:#"..tostring(#v) end,
}
local function describe(v)
local h=handlers[type(v)]
return h and h(v) or "unknown"
end
print(describe(42))
print(describe("hello"))
print(describe({1,2,3}))Valori restituiti covarianti
I metodi delle classi figlie possono restituire tipi più specifici rispetto ai metodi delle classi padre (ritorno covariante). Lua è tipizzato dinamicamente, quindi questo comportamento è naturale: il factory della classe figlia restituisce un'istanza figlia, non soltanto una del padre.
local Base={} Base.__index=Base
function Base.new() return setmetatable({type="base"},Base) end
function Base:copy() return Base.new() end
local Child={} Child.__index=Child
setmetatable(Child,{__index=Base})
function Child.new(extra)
local self=setmetatable({type="child"},Child)
self.extra=extra; return self
end
function Child:copy() return Child.new(self.extra) end -- covariant
local c=Child.new("hello")
local c2=c:copy()
print(c2.extra,getmetatable(c2)==Child) -- hello trueRiepilogo del polimorfismo
Il polimorfismo in Lua, nella pratica, consiste nello stesso nome di metodo con un comportamento diverso per ogni tipo. Si ottiene tramite OOP basato su metatabelle, verifiche di duck typing o tabelle di dispatch. Non è necessario un sistema formale di interfacce: bastano convenzioni coerenti per i nomi dei metodi.
-- Three ways to achieve polymorphism:
-- 1. Metatable inheritance + method override
-- 2. Duck typing: just call it if it exists
-- 3. Dispatch table: map type -> handler
local function area(shape)
-- Duck typing approach:
assert(type(shape.area)=="function","needs area()")
return shape:area()
end
print(area({area=function() return 16 end})) -- 16Domanda sul polimorfismo
Come funziona il polimorfismo in Lua?
Riepilogo: sovrascrittura e polimorfismo
Sovrascriva i metodi della classe padre ridefinendoli nella classe figlia. Lua risolve le chiamate dal basso verso l'alto attraverso la catena __index, ottenendo naturalmente il dispatch polimorfico durante l'esecuzione.
Domande Frequenti
La lezione «Override e polimorfismo» è gratuita?
Sì — il testo completo di «Override e polimorfismo» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Lua Academy, passa a CoddyKit PRO. Il corso Lua Academy include 4 lezioni in totale.
Cosa imparerò in «Override e polimorfismo»?
Esegua l'override dei metodi ereditati e ottenga il dispatch polimorfico a runtime. Eserciti Lua Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Lua Academy?
Non è richiesta alcuna esperienza precedente. Lua Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Override e polimorfismo»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Lua Academy?
Sì. Ogni lezione Lua Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Ereditarietà singola con concatenamento di __index
- Chiamata dei metodi del padre con super
- Pattern mixin
- Override e polimorfismo