Lua 之面向对象编程

Lua 之面向对象编程

Lua并不是为面向对象而设计的一种语言,因此,仅从原生态语法上并不直接支持面向对象编程,但Lua的设计中仍然包含了很多面向对象的思想,理解它们也更有助于理解Lua自身的一些高级机制。

对象

Lua中的table就是一种对象,它可以有函数字段。在面向对象(Object Oriented)编程中,对象的方法(method)通常使用self(或this)参数标识对象自身,在Lua中也可以使用冒号(:)实现类似的功能,如下面的例子:

Account = {balance=0}

function Account:withdraw1(v)
    self.balance = self.balance - v
end

function Account.withdraw2(self, v)
    self.balance = self.balance - v
end

Account:withdraw1(100)
print(Account.balance)

Account.withdraw2(Account, 100)
print(Account.balance)

上面的例子中,withdraw1使用了冒号,隐式使用了self参数;而withdraw2使用了点语法,显式使用self参数;

可以看出,冒号的作用是在一个方法定义中添加一个额外的隐藏参数(self),以及在一个方法调用中添加一个额外的实参。

在C++、python等这样的OO语言中,使用class的语法来创建object(或instance),即每个对象都是特定类的实例。

而在Lua中没有类的概念,也就是说对象是没有类型的,那么要如何创建多个具有类似行为的对象呢?

答案是通过元表的__index元方法,将一个table的__index元方法设置为另一个table,那么后者的方法就被前者继承了。

一个例子:

Humman = {age=0}

function Humman:SetAge(v) self.age=v end
function Humman:GetAge() return self.age end

Chinese = {}
setmetatable(Chinese, {__index = Humman})

Chinese:SetAge(76.3)
print(Chinese:GetAge())

上面的例子中,Chinese会在Humman查找它自己不存在的方法。

甚至可以模仿构造函数的方式来创建对象:

class = {doc=‘hello‘}

function class:new(obj)
    obj = obj or {}
    setmetatable(obj, self)
    self.__index = self
    return obj
end

local a1 = class:new()
print(a1.doc)

这里名为class的这个table就充当了类的作用,通过调用它的new方法,就能返回一个跟它具有类似行为的对象,正如例子中所示,a1对象继承了class的所有字段。

继承

在OO编程思想中,另外一个重要的概念就是继承与派生,即允许由父类派生子类,除了继承基类的行为,子类还可以定义自己独有的行为。

Lua中实现这种特性,仍然是利用了__index元方法的性质——仅在自身没有索引字段时,才会使用__index元方法的返回结果。

一个例子:

Humman = {age=0}

function Humman:SetAge(v) self.age=v end
function Humman:GetAge() return self.age end

function Humman:new(obj)
    obj = obj or {}
    setmetatable(obj, self)
    self.__index = self
    return obj
end

Chinese = Humman:new()

function Chinese:SetAge(v) self.age = v*0.9 end

Beijing = Chinese:new{city=‘bj‘}

Beijing:SetAge(70)
print(Beijing:GetAge()) -- 63

例子中,Chinese继承自Humman,但它重新定义了SetAge方法,而在Beijing这个对象中调用SetAge时,首先查找Chinese,找不到才继续查找 Humman,所以这里,时Chinese的SetAge方法生效了。

上面提供的继承实现思路是将派生类的__index元方法置为代表基类的table,如果要实现多继承,这种方法就不可行了。多继承要求把__index实现为一个函数,它需要遍历所有基类的字段。

一个例子:

parent1 = {a="hello"}
parent2 = {b="world"}

local function search(field, parents)
    for i=1, #parents do
        local v = parents[i][field]
        if v then return v end
    end
end

function createClass(...)

    local c = {}
    local parents = {...}

    setmetatable(c, {__index=function(t, field) return search(field, parents) end} )
    c.__index = c

    function c:new(o)
        o = o or {}
        setmetatable(o, c)
        return o
    end

    return c
end

c = createClass(parent1, parent2)
print(c.a)  -- hello
print(c.b)  -- world

访问权限

我们知道C++的类中,每个成员都有一个访问标签:public、private、protected,通过访问标签来限定对象中每个成员是否对外可见。而通常的做法是将数据成员标记为private,将函数成员标记为public。

前面介绍过Lua的对象是通过table实现的,而table的每个字段都可以直接通过索引访问,因此lua并不打算直接提供对其内部字段访问权限的控制机制。但如果我们一定要让lua对象也实现访问控制,也是有办法的。

一个例子:

function Humman(initialAge)

    local self = {age=initialAge}

    local SetAge = function(v) self.age=v end
    local GetAge = function() return self.age end

    return {GetAge=GetAge, SetAge=SetAge}

end

Chinese = Humman(73)
print(Chinese.GetAge()) -- 73

Chinese.SetAge(80)
print(Chinese.GetAge()) -- 80

上例中,Humman是一个工厂函数,使用它创建了一个Chinese对象。在Humman内部,将类的状态(需要保护的类成员)赋给了一个局部变量,并将类的方法(即类的对外接口)作为一个table返回给了Chinese对象,之后Chinese对象只能通过返回的方法间接操作Humman类的状态,而无法直接访问到它们。

单一方法(single-method)对象

当对象只有一个方法时,将这个单独的方法作为对象返回。比如,一个具有状态的迭代器就是单一方法对象。

单一方法对象还有一种情况,它根据某个参数来完成不同的操作,实现一个类似调度器的功能,例如:

function newObject(value)

    return function(action, v)
    if action == "get" then return value;
        elseif action == "set" then value = v
        else error("invalid action")
        end
    end
end

d = newObject(0)
print(d("get"))

d("set", 10)
print(d("get"))
                 

上面的例子中,返回的单一方法对象用一个closure。

时间: 2024-07-30 19:57:46

Lua 之面向对象编程的相关文章

Lua学习----面向对象编程

1.类 再Lua中可以使用表和函数实现面向对象,将函数和相关的数据放置放置于同一个表中就形成了对象.例如: Measure = {width = 0, height = 0} function Measure:setWifth(v) self.width = self.width + v end function Measure:setHeight(v) self.height = self.height + v end function Measure:getMeasure() print(s

lua的面向对象编程

首先我们去了解一下类,一个类就是一个创建对象的模具,实际上,lua中不存在类这个概念,我们都是去模拟类.在lua中,要表示一个类,只需创建一个专用作其它对象的原型.我们在lua的面相对象,就是使用table,元表以及元方法,我们现在看一下具体事怎么做的: 我们现在有两个对象a和b,现在想b作为a的原型,只需编写下面代码即可: setmetatable(a,{__index = b}) 我们前面有讲过__index,编写完这段代码之后,当lua执行了a没有的操作的时候,就会去b中查询.实际上我们也

【Lua】面向对象编程(一)

类和对象: account.lua   module(...,package.seeall) Account={balance=0} Account.new=function(self,o) local o=o or {} setmetatable(o,self) self.__index=self return o end Account.getBalance=function(self) return self.balance end Account.setBalance=function(

Lua中面向对象编程的理解

模块 模块是一个独立的空间,一个独立的环境,访问模块成员需要先require,并使用"模块名.成员名称"的格式访问.注意:模块是一个table. 类 在lua中所有对象都是一个table,类也是一个table,但类应该是一个只读的table,类的定义是通过创建一个模块实现的. lua代码: module("Student",package.seeall) function study(self) end 在调用module方法时添加package.seeall参数的

Lua面向对象编程

Lua中的table就是一种对象,看以下一段简单的代码: 1 local tb1 = {a = 1, b = 2} 2 local tb2 = {a = 1, b = 2} 3 local tb3 = tb1 4 5 if tb1 == tb2 then 6 print("tb1 == tb2") 7 else 8 print("tb1 ~= tb2") 9 end 10 11 tb3.a = 3 12 print(tb1.a) 上述代码会输出tb1 ~= tb2.

Lua语言基础汇总(12)-- Lua中的面向对象编程

简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 1 2 3 4 5 6 7 8 9 10 11 12 local tb1 = {a = 1, b = 2} local tb2 = {a = 1, b = 2} local tb3 = tb1   if tb1 == tb2 then      print("tb1 == tb2") else      print("tb1 ~= tb2") end   tb3.a = 3 pri

Lua的面向对象——类和继承

本文转载于:http://www.benmutou.com/archives/1791 终于来了,在Lua中的面向对象编程,相信目前学习Lua的大部分人都是为了开发手机网游吧.而且基本都是奔着脚本语言的热更新特性去的,所以全脚本开发变得十分流行. 对于普及不太广的Lua(相对于C++.Java等主流语言),需要短时间上手开发游戏,对新手而言不算简单.所以大家才更习惯于继续用面向对象思想去折腾Lua吧~ 好了,不唠叨了,我最不喜欢唠叨了.(小若:是是是,你一点都不唠叨,赶紧开讲!) 1.类的对象

面向对象编程

面向对象:类,属性,方法 面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的"对象",每个对象都拥有相同的方法,但各自的数据可能不同. 仍以Student类为例,在Python中,定义类是通过class关键字: class Student(object): pass class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下

python面向对象编程

java和c#只支持面向对象编程,python即可支持面向对象也可以支持函数式编程. 面向对象两个重要的概念:  1.类 2.对象 函数式 def sendemail(email,msg):            函数 print("8888") 面向对象 class Myclass: def sendmail(self,email,msg):      函数定义在类中第一个参数必须是self print("8888")              函数在类中定义叫方