【问题标题】:middleclass: add getter-setter support for properties中间类:为属性添加 getter-setter 支持
【发布时间】:2017-02-14 15:05:06
【问题描述】:

我正在尝试添加对属性声明的自动支持,以便类获取自动为它们生成的 getter 和 setter。我使用中间类库作为类的基础。我已经定义了一个处理属性创建的根类。但是,在测试中,只有根类的直接子类才能正常工作。其他人在中间类代码深处给我堆栈溢出错误([string "local middleclass = {..."]:82: stack overflow)。

我的代码是:

local CBaseObject=class('CObjectBase');
function CBaseObject:initialize()
    self._init=true;
end;
function CBaseObject:finalize()
    self._init=false;
end;
function CBaseObject:_getter_setter(v)
    return v;
end;
function CBaseObject:_gen_prop_cache()
    rawset(self,'_properties',rawget(self,'_properties') or {});
end;
function CBaseObject:__index(k)
    print('GET',k);
    self:_gen_prop_cache();
    local prop=self._properties[k];
    if prop~=nil
    then
        local getter=self[prop[2] or '_getter_setter'];
        return getter(self,prop[1]);
    else return nil;end;
end;
function CBaseObject:__newindex(k,v)
    print('ME',self.class.name);
    print('SET',k,v);
    self:_gen_prop_cache();
    local prop=self._properties[k];
    if prop==nil and self._init or prop
    then
        if prop==nil then prop={};self._properties[k]=prop;end;
        local vv=prop[1];
        if type(v)=='table' and #v<4
        then
            for i=1,3 do prop[i]=v[i];end;
        else
            prop[1]=v;
        end;
        local setter=self[prop[3] or '_getter_setter'];
        prop[1]=setter(self,prop[1],vv);
    else
        rawset(self,k,v);
    end;
end;

测试类:

local cls=CBaseObject:subclass('test');
function cls:initialize()
    self.class.super.initialize(self);
    self.health={1000,'_gethealth','_sethealth'};
    self.ammo=100;
    self:finalize();
end;
function cls:_sethealth(value,old)
    print('WRITE:',value,old);
    if value<0 then return old;else return value;end;
end;
function cls:_gethealth(value)
    print('READ:',value);
    return value/1000;
end;

local cls2=cls:subclass('test2');
function cls2:initialize()
    self.class.super.initialize(self);
    self.ammo=200;
    self:finalize();
end;
function cls2:_sethealth(value,old)
    print('WRITE_OVERRIDEN:',value,old);
    return value;
end;
local obj=cls2(); --change this to cls() for working example.
obj.health=100;
obj.health=-100;
print(obj.health,obj._properties.health[1]);
print(obj.ammo,obj._properties.ammo[1]);

我使用https://repl.it/languages/lua 运行我的代码。所以,问题是,我所做的是否是正确的方法?是否可以以与使用的库兼容的更简单方式添加属性支持?或者我应该使用另一个,然后呢?

编辑:经过实验,我发现构造 self.class.parent.&lt;method&gt;(&lt;...&gt;) 是错误的罪魁祸首。我用实际的父类替换了所有此类事件。那是唯一的问题,似乎在那之后代码开始没有错误地工作。

【问题讨论】:

  • 如果您可以自己回答问题,请回答,不要编辑问题...顺便说一句,您可以删除这些分号。在 Lua 中它们不是必需的。
  • 但我仍然不确定我的所作所为不能做得更好。而且我坚持使用分号,因为我不想破坏我在其他语言中需要它们的习惯,基本上所有这些。

标签: oop properties lua


【解决方案1】:

Enrique García Cota (middleclass creator) 用我认为不错的 way to implement getters/setters 中产阶级启发了我。 他建议创建和使用mixin

我在测试/使用这个 mixin 配方时做了一些小改动。目前我使用的是这样的:

-- properties.lua
local Properties = {}

function Properties:__index(k)
    local getter = self.class.__instanceDict["get_" .. k]
    if getter ~= nil then
        return getter(self)
    end
end

function Properties:__newindex(k, v)
    local setter = self["set_" .. k]
    if setter ~= nil then
        setter(self, v)
    else
        rawset(self, k, v)
    end
end

return Properties

您必须为您的属性创建function get_* 和function set_*(或根据需要修改上面的字符串模式)。

例子:

local class = require('middleclass')
local Properties = require('properties')

local Rect = class('Rect'):include(Properties)

function Rect:initialize(x, y, w, h)
  self.x = x
  self.y = y
  self.w = w
  self.h = h
end

function Rect:get_right()
  return self.x + self.w
end

function Rect:set_right(right)
  self.x = self.x + right - self.right
end

r = Rect:new(10,10, 100, 100)

print(r.right) -- 110
print(r:get_right()) -- 110
r.right = 200
print(r.right) -- 200
print(r.x) -- 100

这样你就可以在任何你想拥有属性的类中使用这个 mixin,并且只需在上面创建 get_* 和 set_* 函数。

然而,他也说:

我不是 Lua 中的 getter/setter 的忠实粉丝。其他语言,我可以接受;例如在 ruby​​ 中,它们被集成在语言的消息传递机制中。

但在 Lua 中,它们是额外的语法糖,并且有可能使事情变得更加“神奇”(对于不熟悉代码的人来说是意想不到的)。

性能说明:但是,值得一提的是,像示例一样使用 __index 函数会严重影响代码的性能(如果与 __index 表相比)。 就个人而言,在使用 getter 和 setter 一段时间后(由于我对 Python 的偏见),我决定明确地编写东西,不再依赖它们。 当然,这取决于性能是否对您的代码至关重要。

【讨论】:

    猜你喜欢
    • 2021-11-06
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2011-04-27
    • 1970-01-01
    相关资源
    最近更新 更多