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 = {
|
||||
name = "MyClass",
|
||||
sayHello = function(self)
|
||||
print("Hello from " .. self.name)
|
||||
local function MyClass(cls)
|
||||
cls.setattr(cls, "name")
|
||||
|
||||
function cls.__init(this, name)
|
||||
this.name = name
|
||||
end
|
||||
}
|
||||
|
||||
obj = utils.deepcopy(class)
|
||||
obj.name = "Carl"
|
||||
obj.sayHello(obj) -- Output: Hello from Carl
|
||||
function cls.test(this, name)
|
||||
print("hi " .. this.name .. " from " .. name)
|
||||
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 @@
|
||||
--[[
|
||||
the plan is to create a simple oop system in lua
|
||||
local oop = {}
|
||||
|
||||
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
|
||||
with at least the concept of self
|
||||
]]
|
||||
local function_def_cache = setmetatable({}, { __mode = "k" })
|
||||
|
||||
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