Lua 之面向对象编程
Lua 之面向对象编程
Lua并不是为面向对象而设计的一种语言,因此,仅从原生态语法上并不直接支持面向对象编程,但Lua的设计中仍然包含了很多面向对象的思想,理解它们也更有助于理解Lua自身的一些高级机制。
对象
Lua中的table就是一种对象,它可以有函数字段。在面向对象(Object Oriented)编程中,对象的方法(method)通常使用self(或this)参数标识对象自身,在Lua中也可以使用冒号(:)实现类似的功能,如下面的例子:
Account = {balance=}
function Account:withdraw1(v)
self.balance = self.balance - v
end
function Account.withdraw2(self, v)
self.balance = self.balance - v
end
Account:withdraw1()
print(Account.balance)
Account.withdraw2(Account, )
print(Account.balance)
上面的例子中,withdraw1使用了冒号,隐式使用了self参数;而withdraw2使用了点语法,显式使用self参数;
可以看出,冒号的作用是在一个方法定义中添加一个额外的隐藏参数(self),以及在一个方法调用中添加一个额外的实参。
类
在C++、python等这样的OO语言中,使用class的语法来创建object(或instance),即每个对象都是特定类的实例。
而在Lua中没有类的概念,也就是说对象是没有类型的,那么要如何创建多个具有类似行为的对象呢?
答案是通过元表的__index元方法,将一个table的__index元方法设置为另一个table,那么后者的方法就被前者继承了。
一个例子:
Humman = {age=}
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=}
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()
print(Beijing:GetAge()) --
例子中,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=, #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()
print(Chinese.GetAge()) --
Chinese.SetAge()
print(Chinese.GetAge()) --
上例中,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()
print(d("get"))
d("set", )
print(d("get"))
上面的例子中,返回的单一方法对象用一个closure。
Lua 之面向对象编程的更多相关文章
- Lua学习----面向对象编程
1.类 再Lua中可以使用表和函数实现面向对象,将函数和相关的数据放置放置于同一个表中就形成了对象.例如: Measure = {width = 0, height = 0} function Mea ...
- 【Lua】面向对象编程(二)
多重继承: module(...,package.seeall) local function search(k,plist) ,#plist do local v=plist[i][k] if ...
- 【Lua】面向对象编程(一)
类和对象: account.lua module(...,package.seeall) Account={balance=} Account.new=function(self,o) local ...
- Lua面向对象编程
Lua中的table就是一种对象,看以下一段简单的代码: , b = } , b = } local tb3 = tb1 if tb1 == tb2 then print("tb1 == t ...
- Lua中的面向对象编程详解
简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 复制代码代码如下: local tb1 = {a = 1, b = 2}local tb2 = {a = 1, b ...
- 云风:我所偏爱的C语言面向对象编程范式
面向对象编程不是银弹.大部分场合,我对面向对象的使用非常谨慎,能不用则不用.相关的讨论就不展开了. 但是,某些场合下,采用面向对象的确是比较好的方案.比如 UI 框架,又比如 3d 渲染引擎中的场景管 ...
- 一步步分析:C语言如何面向对象编程
这是道哥的第009篇原创 一.前言 在嵌入式开发中,C/C++语言是使用最普及的,在C++11版本之前,它们的语法是比较相似的,只不过C++提供了面向对象的编程方式. 虽然C++语言是从C语言发展而来 ...
- angular2系列教程(六)两种pipe:函数式编程与面向对象编程
今天,我们要讲的是angualr2的pipe这个知识点. 例子
- 带你一分钟理解闭包--js面向对象编程
上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...
随机推荐
- C++11特性:auto关键字
前言 本文的内容已经不新鲜了.关于auto,翻来覆去被人知道的都是这些东西,本文并没有提出新颖的auto用法. 本人原是痛恨博客一篇篇都是copy而来缺乏新意的探索,当然,本文不是copy而来,但发布 ...
- C语言之贪吃蛇
利用链表的贪吃蛇,感觉自己写的时候还是有很多东西不熟悉, 1.预编译 2.很多关于系统的头文件也不是很熟悉 3.关于内存 第一个是.h头文件 #ifndef _SNAKE_H_H_H #define ...
- Hive UDF开发实例学习
1. 本地环境配置 必须包含的一些包. http://blog.csdn.net/azhao_dn/article/details/6981115 2. 去重UDF实例 http://blog.csd ...
- linux中/和/root(~) 和 /home
winodws是森林型目录结构,它有很多根,如C.D.E.F等都是它的根目录,然后在其实创建子目录linux是树型目录结构,它只有一个根就是/目录,然后在/目录在有子目录如/root./home./e ...
- springMVC-JSR303数据效验
JSR 303 是java为Bean数据合法性校验提供的标准框架, 它已经包含在javaEE6.0中 JSR 303 通过Bean属性上标注类似于@NotNull.@Max等标准的注解指定校验规则, ...
- JSP的JSTL标签使用
JSTL标签和asp.net中的webform控件很像,但是功能确比asp.net的强很多. 配置过程,从最简单的项目开始: 1.下载JSTL标签库:http://archive.apache.org ...
- 用python虚拟串口
在linux下调试串口程序,无奈下面的硬件还没到位,所以,想着自己模拟一个串口用用.试了下下面这段代码: #!/usr/bin/env python #coding=utf-8 import pty ...
- UVa 7146 Defeat the Enemy(贪心)
题目链接: 传送门 Defeat the Enemy Time Limit: 3000MS Memory Limit: 32768 KB Description Long long ago t ...
- [JavaEE]Get请求URI中带的中文参数在服务端乱码问题的解决方法
在Get请求中,如果请求参数中带有中文,如 http://localhost:8080/DinnerParty/shop/search?query=多伦多, 在服务端拿到的是乱码. 这是因为客户端提交 ...
- bootstrap学习总结-05 常用标签3
1 单选框,多选框 1)单选框 单选框(radio)用于从多个选项中只选择一个.设置了 disabled 属性的单选或多选框都能被赋予合适的样式.对于和多选或单选框联合使用的 <label> ...