gpt4 book ai didi

class - 构建 Lua 类

转载 作者:行者123 更新时间:2023-12-05 01:22:17 28 4
gpt4 key购买 nike

我正在 Lua 中构建一个类,其中包含许多相关函数组,但不确定是否有更好的方法来构建它。我目前必须为 Lua 5.1 环境进行开发,但我希望 Lua 5.3 在不久的将来成为可能。

该类将在许多不同的 Lua 程序中使用,所以我想要一些可以作为单个代码块放入的东西(我正在编程的环境意味着模块和 require 不是也不会是选项)。

理想情况下,我想要一段黑盒代码(公开的公共(public)方法除外),而不是在不同的类中重复代码(以提高可维护性)。

我目前拥有的是(广义的):

 function Fclass()

--here I declare a bunch of local functions that can be called by any of the public methods

local function A(parms)
end

--Public methods set 1

--here I declare a bunch of state variables shared by BSelector and GetB

local BSelector = function()
A(parmvalues)
--returns a bunch of iup controls with supporting (complicated) logic
end

local GetB = function()
--returns the values of the iup controls created in Bselector
end

--Public methods set 2

--here I declare a bunch of state variables shared by DSelector and GetD

local DSelector = function()
--returns a bunch of iup controls with supporting (complicated) logic
end

local GetD = function()
A(parmvalues)
--returns the value of the iup controls created in Dselector
end

return{BSelector =BSelector , GetB =GetB, DSelector =DSelector , GetD =GetD}
end

“B”和“D”组方法是完全独立的,除了它们都使用局部函数“A”等(不依赖于外部变量);理想情况下,它们的状态变量应该是 团体本地人 .

这是一个合理的结构吗?或者我应该将“B”和“D”组分成两个单独的类,然后复制本地函数或将它们作为单独的代码放入?我真的不想在类之外公开本地函数,因为不可避免地会发生命名冲突......大多数程序将使用所有方法组,尽管有些程序只使用一个组。

还是有更好的方法来做到这一点?

我这样调用它们:
myB = Fclass()
myD = Fclass()
someresults = myB.Bselector()
otherresults = myD.Dselector()

更新添加:我被告知我可能没有正确使用术语,我正在做的不是类(class)。我的方法是基于 Programming in Lua并被选中是因为我想保留类(class)的状态变量?目的?私有(private)的——只能通过公共(public)方法访问。

最佳答案

在您的示例中,您似乎通过闭包而不是表值封装了实例的状态。

虽然这具有封装性更强的优点,因为在不使用调试库的情况下,upvalues 从外部是不可见的,但它也带来了 Lua 必须关闭每个实例的每个方法,浪费更多内存(虽然不是很多)的缺点。

另一个好处是,当实例变量实现为表字段时,它们不需要在方法之前声明,因为表索引是基于字符串的,而当实现为闭包时,需要在定义函数之前知道局部变量(这也适用于其他方法,它们在任一实现中的工作方式与实例变量相同)。

更常见的做法是将实例变量存储为对象内的表值,并将对象作为第一个参数传递给函数。 There's even syntactic sugar for this .

在 Lua 中有很多方法可以做类,有很多不同的权衡(有些更擅长继承,而另一些表现更好,等等)

由于您似乎不需要任何继承,因此您可以使用简单的工厂函数,因为您已经在做很多事情了。

我个人喜欢构建此类工厂函数的方式是:

local object do
local class = {}
local meta = {__index=class} -- Object metatable

function class:print() -- A method of the class
print("Hello, I am an object and my x is " .. tostring(self.x))
end

function object(self) -- The factory function for the Class
self.x = self.x or 0
return setmetatable(self, meta)
end
end

local o = object {
x = 20
}
o:print()
o.x = 30
o:print()

这样做的好处是,对于具有许多方法和许多实例的类,方法不会复制到每个实例中,这样可以节省一些内存。

或者,你可以做这样的事情

local object do
local function object_print(self)
print("Hello, I am an object and my x is " .. tostring(self.x))
end

function object(self)
self.x = self.x or 0
self.print = object_print -- Store method directly in the object
return self
end
end

同样,这会在每个实例中保存对每个方法的引用,从而浪费一些内存。好处是您现在可以将类视为特征。当你写

person { name = "henry" }

您可以将其视为创建一个名为 Henry 的新人,但您也可以将其视为创建一个名为 Henry 的对象并向其添加人员特征。

由于将 OOP 的两个概念结合到一个实现中并且没有任何令人讨厌的继承的好处,在大多数简单的情况下,这是我最喜欢在 Lua 中构建对象的方式。

更新

trait 方法也适用于一起定义多个类/特征:

local person, human do
-- Some generic method shared by both classes
local function object_get_name(self)
return self.name
end
-- Person uses this as a method, but human uses
-- it as a function through an upvalue. Both work,
-- but have different upsides and downsides.

-- A method of person
local function person_say_hi(self)
print(self:get_name() .. " says hi!")
-- Calling get_name as a method here
end

-- A method of human
local function human_describe(self)
print(object_get_name(self) .. ' is a human!')
-- Calling get_name as an upvalue
end

function person(self)
self.name = self.name or 'A person'
self.say_hi = person_say_hi
self.get_name = object_get_name
-- Needs to be a method because person_say_hi assumes it to be one
return self
end

function human(self)
self.name = self.name or 'A human'
self.describe = human_describe
return self
end
end

-- Create a new person
local henry = person{ name = "Henry" }
henry:say_hi()

-- Create a new human
local steve = human { name = "Steve" }
steve:describe()

-- Change the way henry gets his name
function henry:get_name()
return self.name:upper()
end
-- This only affects henry; all other "person" objects keep their old
henry:say_hi()
-- This only works because say_hi accesses the method

-- Add the person trait to steve
person(steve)
steve:describe() -- Steve is still a human
steve:say_hi() -- Steve is also a person now

关于class - 构建 Lua 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59704022/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com