Refactor OOP implementation: replace class-based structure with a function-based approach and enhance method definitions
This commit is contained in:
parent
c0c37059d6
commit
b32a9d8786
22
main.lua
22
main.lua
@ -1,12 +1,16 @@
|
|||||||
utils = require("oop/utils")
|
oop = require("oop/oop")
|
||||||
|
|
||||||
class = {
|
local function MyClass(cls)
|
||||||
name = "MyClass",
|
cls.setattr(cls, "name")
|
||||||
sayHello = function(self)
|
|
||||||
print("Hello from " .. self.name)
|
function cls.__init(this, name)
|
||||||
|
this.name = name
|
||||||
end
|
end
|
||||||
}
|
|
||||||
|
|
||||||
obj = utils.deepcopy(class)
|
function cls.test(this, name)
|
||||||
obj.name = "Carl"
|
print("hi " .. this.name .. " from " .. name)
|
||||||
obj.sayHello(obj) -- Output: Hello from Carl
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local obj = oop.new(MyClass, "Carl")
|
||||||
|
obj.test("tom") -- Output: hi Carl from tom
|
||||||
|
|||||||
128
oop/oop.lua
128
oop/oop.lua
@ -1,9 +1,125 @@
|
|||||||
--[[
|
local oop = {}
|
||||||
the plan is to create a simple oop system in lua
|
|
||||||
|
|
||||||
it might not work liky python
|
local function super_call(self, method_name, ...)
|
||||||
|
local class = getmetatable(self)
|
||||||
|
if not class then
|
||||||
|
error("super() called on non-instance")
|
||||||
|
end
|
||||||
|
local base = rawget(class, "__base")
|
||||||
|
if not base then
|
||||||
|
error("super() called but no base class")
|
||||||
|
end
|
||||||
|
local fn = base[method_name]
|
||||||
|
if not fn then
|
||||||
|
error("base class has no method '" .. tostring(method_name) .. "'")
|
||||||
|
end
|
||||||
|
return fn(self, ...)
|
||||||
|
end
|
||||||
|
|
||||||
think of it more like a facory system
|
local function_def_cache = setmetatable({}, { __mode = "k" })
|
||||||
with at least the concept of self
|
|
||||||
]]
|
|
||||||
|
|
||||||
|
function oop.setattr(target, key, value)
|
||||||
|
target[key] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
function oop.new(class, ...)
|
||||||
|
local actual_class = class
|
||||||
|
if type(class) == "function" then
|
||||||
|
actual_class = function_def_cache[class]
|
||||||
|
if not actual_class then
|
||||||
|
actual_class = oop.class(class)
|
||||||
|
function_def_cache[class] = actual_class
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local obj = setmetatable({}, actual_class)
|
||||||
|
if actual_class.__init then
|
||||||
|
actual_class.__init(obj, ...)
|
||||||
|
end
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
|
||||||
|
local function lookup_in_class(cls, key)
|
||||||
|
local cur = cls
|
||||||
|
while cur do
|
||||||
|
local val = rawget(cur, key)
|
||||||
|
if val ~= nil then
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
cur = rawget(cur, "__base")
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function oop.class(def, base)
|
||||||
|
local cls = {}
|
||||||
|
cls.__name = "Anonymous"
|
||||||
|
cls.__base = base
|
||||||
|
cls.__index = function(self, key)
|
||||||
|
local val = lookup_in_class(cls, key)
|
||||||
|
if type(val) == "function" then
|
||||||
|
return function(...)
|
||||||
|
return val(self, ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
|
||||||
|
function cls:super(method_name, ...)
|
||||||
|
return super_call(self, method_name, ...)
|
||||||
|
end
|
||||||
|
function cls.setattr(target, key, value)
|
||||||
|
return oop.setattr(target, key, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
setmetatable(cls, {
|
||||||
|
__index = base,
|
||||||
|
__call = function(c, ...)
|
||||||
|
return oop.new(c, ...)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
||||||
|
if type(def) == "string" then
|
||||||
|
cls.__name = def
|
||||||
|
elseif type(def) == "function" then
|
||||||
|
def(cls)
|
||||||
|
elseif def ~= nil then
|
||||||
|
error("class definition must be a function or name string")
|
||||||
|
end
|
||||||
|
|
||||||
|
return cls
|
||||||
|
end
|
||||||
|
|
||||||
|
function oop.isinstance(obj, class)
|
||||||
|
local mt = getmetatable(obj)
|
||||||
|
while mt do
|
||||||
|
if mt == class then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
mt = rawget(mt, "__base")
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function oop.issubclass(class, base)
|
||||||
|
local mt = class
|
||||||
|
while mt do
|
||||||
|
if mt == base then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
mt = rawget(mt, "__base")
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function oop.install(env)
|
||||||
|
local target = env or _G
|
||||||
|
target.class = oop.class
|
||||||
|
target.new = oop.new
|
||||||
|
target.setattr = oop.setattr
|
||||||
|
target.isinstance = oop.isinstance
|
||||||
|
target.issubclass = oop.issubclass
|
||||||
|
end
|
||||||
|
|
||||||
|
oop.install()
|
||||||
|
|
||||||
|
return oop
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user