我想在Lua中进行一些面向对象的编程,因此我决定采用以下方法:

 local B = {} -- in real life there is other stuff in B

B.Object = {

  constructor = function() end,

  extend = function(this, that, meta)
    if not that then that = {} end
    if not meta then meta = {} end
    meta.__index = this
    setmetatable(that, meta)
    return that
  end,

  isa = function(this, that)
    for meta in function() return getmetatable(this) end do
      if this == that then return true end
      this = meta.__index
    end
    return this == that
  end,

  new = function(this, ...)
    local that = this:extend()
    that:constructor(...)
    return that
  end,

}
 


所有对象(包括“类对象”)都直接或间接扩展了B.Object。例如:

 -- Request handler base

B.RequestHandler = B.Object:extend()

-- override these
function B.RequestHandler:accept() error "not implemented" end
function B.RequestHandler:process() error "not implemented" end

-- URL-encoded POST handler

B.PostHandler_URLEncoded = B.RequestHandler:extend()

function B.PostHandler_URLEncoded:accept()
  return self.method == "POST" and 
         self.content_type == "application/x-www-form-urlencoded"
end

function B.PostHandler_URLEncoded:process()     
  -- some code
end

-- Multipart POST handler

B.PostHandler_Multipart = B.RequestHandler:extend()
-- etc.
 


它可能会被这样使用:

 B.request_handlers = {
  GetHandler:new(),
  URLEncodedPostHandler:new(), 
  MultipartPostHandler:new(), 
}

B.handle_request = function()
  for k, v in ipairs(B.request_handlers) do
    if v:accept() then
      return v:process()
    end
  end
  error "request not handled"
end
 


据我所知,这几乎是Lua中处理继承的正常方法。我想念什么吗?有什么需要改进的吗?

评论

我建议添加一些注释来描述您的代码的意图。最大的问题可能是私有财产。我前段时间尝试了一些想法,但是每个选项要么都非常不完整(因此将需要大量样板代码),要么将至少两个级别引入到调用堆栈中。所以我的建议是:尝试不继承。无需继承即可解决大多数代码复制问题。

#1 楼

示例用法

您提供的示例并没有真正帮助解释代码应如何工作。我相信它确实可以工作,但是变量并不完全匹配。例如,下面的代码是:

B.request_handlers = {
  GetHandler:new(),
  URLEncodedPostHandler:new(), 
  MultipartPostHandler:new(), 
}


什么在此之前是B.request_handlers?您可以像在前面的代码块中那样定义“类”:B.RequestHandler = B.Object:extend(),但现在它是小写字母并带有下划线。这些括号内的三个电话的情况相同。 GetHandler叫什么?我在任何地方都找不到匹配的方法。只是有点混乱。

缺少注释

第一个代码块是最重要的代码块,因为这是您建立实际Lua继承的地方。代码的问题在于它非常密集,并且没有任何关于预期如何使用的解释。

例如,您定义如下的extend方法:

extend = function(this, that, meta)
  if not that then that = {} end
  if not meta then meta = {} end
  meta.__index = this
  setmetatable(that, meta)
  return that
end,


,但是在您的示例中,您可以这样称呼它:

B.RequestHandler = B.Object:extend()


阅读完该方法后,我可以理解如果调用extend()时不带任何参数,则参数将填充在方法内部。我认为发表评论解释调用extend方法的有效方法将非常有帮助。在大多数语言中,当方法具有参数时,必须提供它们,否则编译器会抱怨。由于Lua是一种动态语言,您将无法进行检查,因此我认为解释如何使用OOP实现的注释变得更加重要。

这个,那个和另一个

此代码很难理解:

isa = function(this, that)
  for meta in function() return getmetatable(this) end do
    if this == that then return true end
    this = meta.__index
  end
  return this == that
end,

new = function(this, ...)
  local that = this:extend()
  that:constructor(...)
  return that
end,


所有那个,那个,然后,这个==那个,返回那个,等等等等只会使我的大脑扭成一个结。如果我非常仔细地逐行阅读代码,最终我会弄不清楚它的作用,但是我认为这是代码的失败。

没错,您可能不打算让任何人阅读您的继承代码。相反,一旦设置完成,它将可以正常工作,并允许使用该代码的人以经典的OOP方式扩展对象。但是,我仍然认为,通过使用更好的变量名,一些注释和更多的代码行,可以这样编写它,以便在阅读时可以立即理解它。

也认为不是说英语的人可能会为此而感到困惑,那么then关键字对情况无济于事。

东西不错

我喜欢这段代码在这里:

-- override these
function B.RequestHandler:accept() error "not implemented" end
function B.RequestHandler:process() error "not implemented" end


该注释非常清楚,这些是应重写的方法,如果没有,将返回的字符串将使很清楚出了什么问题。