So, overtime I learned how to improve my OOP code, from having a separate metatable for each object, to combining everything under one table, and using some neat ‘tecnics’ I like.
Essentially how I code OOP code now a days, is something like this:
local Object = {};
Object.__index = Object;
Object.ClassName = 'Object'
function Object:IsA(...)
return ... == self.ClassName
end
return Object
I pretty much always have a :IsA() function, and I use it for checking. Let’s say I have a bunch of classes but I don’t wanna have every single one with a new ‘class’, what I will do is something like this:
function Service:LoadData()
assert(self:IsA('Service'), 'You can only call :LoadData() from the Service!')
--\\ run code here
end
Every single new object from a different class will have a unique .ClassName, and all functions will then have a :IsA() check, and only allow them to be ran if the class matches.
And essentially I believe that keeps my code clean.
The :IsA() part seems a bit unnecessary to me. I think that your idea is to recycle your classes as much as possible, rather than creating them over and over again. What you are probably looking for is ‘Design Patterns’ in OOP. These patterns are essentially standard solutions for structuring the way that your classes interact with each other (see https://www.oodesign.com/). This way, you can design the structure of your code before you write it (then you will probably not need :IsA() anymore.
By convention the module is the class and the objects are the things it makes from its constructor function, referencing the first sample. That’s provided what you’re writing there is a class. Not a problem if your class is literally Object but it’s a little strange for nomenclature.
As for the IsA method, conventionally for OOP-in-Lua you would use an Is class-level function (not a method) if you want to perform object class checking. A really simple way would be to compare if the metatables point to the same table. Other ways I’ve seen include checking a class-level property (you already have ClassName there), though that’s a little longer to write out.
local Class = {}
Class.__index = Class
Class.ClassName = "Class"
function Class.Is(object)
return typeof(object) == "table" and getmetatable(object) == Class
end
If you’re looking to test or understand how to test it:
local foobar = setmetatable({}, Class)
print(Class.Is(foobar)) --> true
Don’t really understand the purpose of locking method calls unless Is(A) returns true though since objects you create of a class implicitly will only be given that class’s items, unless you’re doing some kind of middleclass or other pattern that isn’t being shown here. It’s not necessary. Pretty sure even with a middleclass you would not need to do that.