Lua
Orientacja obiektowa
Szukaj…
Wprowadzenie
Sama Lua nie oferuje systemu klasowego. Możliwe jest jednak zaimplementowanie klas i obiektów jako tabel za pomocą kilku sztuczek.
Składnia
function <class>.new() return setmetatable({}, {__index=<class>}) end
Prosta orientacja obiektu
Oto podstawowy przykład wykonania bardzo prostego systemu klas
Class = {}
local __instance = {__index=Class} -- Metatable for instances
function Class.new()
local instance = {}
setmetatable(instance, __instance)
return instance
-- equivalent to: return setmetatable({}, __instance)
end
Aby dodać zmienne i / lub metody, po prostu dodaj je do klasy. Oba można zastąpić dla każdej instancji.
Class.x = 0
Class.y = 0
Class:getPosition()
return {self.x, self.y}
end
I aby utworzyć instancję klasy:
object = Class.new()
lub
setmetatable(Class, {__call = Class.new}
-- Allow the class itself to be called like a function
object = Class()
I aby go użyć:
object.x = 20
-- This adds the variable x to the object without changing the x of
-- the class or any other instance. Now that the object has an x, it
-- will override the x that is inherited from the class
print(object.x)
-- This prints 20 as one would expect.
print(object.y)
-- Object has no member y, therefore the metatable redirects to the
-- class table, which has y=0; therefore this prints 0
object:getPosition() -- returns {20, 0}
Zmienianie meta metod obiektu
Mający
local Class = {}
Class.__meta = {__index=Class}
function Class.new() return setmetatable({}, Class.__meta)
Zakładając, że chcemy zmienić zachowanie obiektu z pojedynczą instancją object = Class.new()
za pomocą metatable,
jest kilka błędów, których należy unikać:
setmetatable(object, {__call = table.concat}) -- WRONG
Wymienia to stare metatable na nowe, tym samym przerywając dziedziczenie klas
getmetatable(object).__call = table.concat -- WRONG AGAIN
Należy pamiętać, że „wartości” z tabeli są jedynie odniesieniem; w rzeczywistości istnieje tylko jedna rzeczywista tabela dla wszystkich instancji obiektu, chyba że konstruktor jest zdefiniowany jak w 1 , więc w ten sposób modyfikujemy zachowanie wszystkich instancji klasy.
Jeden poprawny sposób to zrobić:
Bez zmiany klasy:
setmetatable(
object,
setmetatable(
{__call=table.concat},
{__index=getmetatable(object)}
)
)
Jak to działa? - Tworzymy nowy metatabilny jak w pomyłce nr 1, ale zamiast pozostawiać go pustym, tworzymy miękką kopię do oryginalnego metatable. Można powiedzieć, że nowe metatowalne „dziedziczy” po oryginalnym, jakby to była sama instancja klasy. Możemy teraz zastąpić wartości oryginalnego metatable bez ich modyfikowania.
Zmiana klasy:
1. (zalecane):
local __instance_meta = {__index = Class.__meta}
-- metatable for the metatable
-- As you can see, lua can get very meta very fast
function Class.new()
return setmetatable({}, setmetatable({}, __instance_meta))
end
2. (mniej zalecane): patrz 1
1 function Class.new() return setmetatable({}, {__index=Class}) end