lua oop[0]:实现基本的OO 框架

来源:互联网 发布:2016淘宝规则好评返现 编辑:程序博客网 时间:2024/06/05 02:22

lua虽然原生面向对象,不过它提供了一些功能,使得我们很容易模拟出对象

云风以前也实现过一次,代码有点复杂,我想重新实现一些。

目标

实现一个Class 函数,它接收一个构造函数,然后返回一个生成器,每次调用这个生成器可以生成一个新的对象。

具体用法如下:

package.path=package.path..";./code/luagy/?.lua;./luagy/?.lua"Class=require("grammar.class")baseclass=Class(function (self,x) --构造函数    self.x=x    print ("baseclass init ")    self:fn(x)  end)baseclass.level=1 --属性function baseclass:fn(x) --方法  print("call baseclass fn")  self.x=xendbaseobj1=baseclass(1) --新建对象baseobj2=baseclass(2)print(baseobj1.x,baseobj2.x)baseobj2:fn(3)print(baseobj1.x,baseobj2.x) baseobj1.level=3print(baseclass.level,baseobj2.level,baseobj1.level)

实现

用了十多行实现了基本的功能:

local function Class( _ctor)  local c = {} --生成器  c.__index = c  --对象要从类索引方法等  c._ctor = _ctor --保留构造函数  setmetatable(c, {__call = function(class_tbl, ...)    local obj = {} --新的对象    setmetatable(obj,c)    if c._ctor then      c._ctor(obj,...)    end    return obj  end})  return cendreturn Class

继承

下面来实现关于的类的继承

目标是实现类似下面的调用

childclass1=Class(baseclass,function (self,y)    self.y=yend)co1=childclass1(3)co1:fn(2)print(co1.x,co1.y,co1.level)

只要把Class 函数的参数改成两个,如果第一个参数类型是函数的话,说明它是一个基类,不用从父类复制方法和属性,相反,如果是table,就复制父类的所有属性的方法到子类,然后用第二个参数构造生成器。

这也就是为什么Class返回的是table而不是函数的原因之一

具体如下:

local function Class(base, _ctor)  local c = {} --生成器  if not _ctor and type(base) == 'function' then    --基类    _ctor = base    base = nil  elseif type(base) == 'table' then    --复制父类的方法    for i,v in pairs(base) do      c[i] = v    end    c._base = base  end   c.__index = c  --对象要从类索引方法等  c._ctor = _ctor --保留构造函数  setmetatable(c, {__call = function(class_tbl, ...)    local obj = {} --新的对象    setmetatable(obj,c)    if c._ctor then      c._ctor(obj,...)    end    return obj  end})  return cendreturn Class

这样一个基本的 OO框架就完成了,不过还有许多的问题。
首先,在从父类复制属性时,是利用浅复制,假如属性的类型是table,修改子类的该属性,父类的也会跟着改变。
或者可以这样解决:

  • 对于特殊的类型(如table) 递归复制,直到所有变量都为基本类型为止,但是有些类型(userdata)并不能进行深复制,要有对应的复制函数
  • 将属性的定义放在一个特殊的函数里,每次构造新对象重新生成属性,这样的代码基本上不用改动,问题就得到解决

由于每一次新建一个类时,父类的构造函数被重载了,所以要调用父类的构造函数只能这样

cc2=Class(baseclass,function (self)    self._base._ctor(self)    ...end)

还有,因为使用了元表,但是lua的实现中元表是不能无限嵌套的(防止无限递归)所以下面的代码会出错

1 0
原创粉丝点击