《Programming in Lua 3》读书笔记(十二)

日期:2014.7.14     

PartⅡ Object-Oriented Programming

Lua中实现面向对象编程。
“如同OOP对象,table拥有状态;如同OOP对象,table拥有标识符---self,用来与其他变量做区分,而且两个table拥有同样的值也是不同的object(对象),因为self的不同;如同OOP对象,table也有生命周期,这个生命周期与谁在何处创建table是保持独立的”

对象是拥有自己的运算操作的,table也有,如
e.g.
Account = {blanche = 0}
function Account.withdraw(v)Account.balance = Account.balance - v
end
上述的函数就是OOP中称呼的method(方法)。当然,上述的使用技巧是不可取的:在函数体内使用全局变量Account。这样会造成严重的后果,而且这样使用限制性太大,当我们改变了变量类型,这个操作就失效了。这种操作与面向对象编程中对象保持独立的生存周期这一原则相悖。
e.g.
a , Account = Account,nil
a.withdraw(100.00)          --error
因为我们将Account赋值为nil了,所以withdraw函数就会报错。

针对上述的操作改进:我们可以传递额外的参数,作为函数运算的对象
e.g.
function Account.withdraw(self,v)self.balance = self.balance - v
end
此时
a , Account = Account,nil
a.withdraw(100.00)          --ok

但是在大多数面向对象编程的语言中,一般都是隐藏我们上述用到的那个参数。Lua也能隐藏这个参数,这里就要使用到冒号操作符
e.g.
function Account:withdraw(v)self.balance = self.balance - v
end
当然,这里使用冒号操作符只是一个语法约定而已,没有额外的意思。我们可以用点号运算符定义一个函数然后用冒号运算符调用该函数,反之亦然
e.g.
Account = {balance = 0,withdraw = function (self,v)self.balance = self.balance - vend}
function Account:deposit (v)self.balance = self.balance + v
end
Account.deposit(Account,200)

我个人还是觉得按套路来,遵循这种语法约定。


16.1 Classes
Lua中没有类(class)的概念,但是很容易模仿出类。参考了prototype-base language(面向原型编程)中prototype(原型)的相关技巧。在这种语言中,也是没有类,但是每个对象都拥有一个原型。在这种语言环境下要表现出类的概念,我们只需要为继承者创建一个唯一的对象作为原型。类和原型的目的都在于共享某些行为。

前面在讨论元表的时候有提到继承,因此假如现在有两个对象a和b,采用如下操作便可将b设置为a的原型:
e.g.
setmetatable(a,{__index = b})
执行了这个操作之后,假如我们访问a中的成员,在找不到的时候会访问b。

回到现在讨论的类,假如我们需要创建一个新的account,其行为与Account一样,在这里我们就可以考虑使用继承,使用 __index 元方法。在这里我们不需要额外创建一个新的table作为元表,可以直接将我们要继承的table设置为其元表:
e.g.
function Account:new(o)o = o or {}setmetatable(o,self)self.__index = selfreturn o
end
这里使用到了前文提到的冒号操作符,默认使用了self参数。
此时
a = Account:new(balance = 0}
a:deposit(100.00)
我们新建了一个table  a,其元表为Account,又修改了其元方法__index 为Account 自身,当我们在a中寻找deposit的时候,找不到的时候会自动在Account中寻找,达到了继承的要求。
创建a的时候,将balance赋值为了0,假如不给其赋值,则会继承其默认值
b = Account:new()
print(b.balance)               --- 0     继承了Account的balance的值0


16.2 Inheritance
继承
Lua中实现继承还是比较容易的
e.g.
--基类
Account = {balance = 0 }
function Account:new(o)o = o or {}setmetatable(0,self)self.__index = selfreturn o
end
function Account:deposit(v)self.balance = self.balance + v
end
function Account:withdraw(v)if v > self.balance then error "xxx" endself.balance = self.balance - v
end

现在我们想写一个子类继承这个基类,然后能在子类中做进一步的修改,可以这样操作
SpecialAccount = Account:new()
执行以上操作之后,SpecialAccount 便是Account的一个实例了(--modify 应该是继承而非实例吧?),当我们执行一下操作:
s = SpecialAccount:new(limit = 1000.00}
SpecialAccount 从基类中继承了new这个方法,因为这里使用了冒号操作符,默认使用了SpecialAccount这个参数,因此此时s的元表是SpecialAccount。当我们试图访问s中不存在的元素的时候,便会去SpecialAccount中寻找,而从SpecialAccount中寻找不到的时,转而会去Account中寻找。
e.g.
s:deposit(100.00)
此时lua会在s、SpecialAccount、Account里面寻找deposit方法

我们可以在子类中重新定义从基类中继承的方法:
e.g.
function SpecialAccount:withdraw(v)if v - self.balance >= self.getLimit() thenerror"xx"endself.balance = self.balance - v
end
function SpecialAccount:getLimit()return self.limit or 0
end

此时,当我们调用s:withdraw的时候,lua会直接在SpecialAccount找到该方法,执行该方法内的操作。
而lua中有趣的一点是,不需要重新创建一个新的类来实现一个新的行为,可以直接在对象中实现该行为,如:
上文我们已经创建了SpecialAccount对象s,我们要在s中实现一个限制行为,限制每次的操作限额,我们可以这样实现:
e.g.
function s:getLimit()return self.balance * 0.10
end
这样,当我们调用s:withdraw的时候,条件判断getLimit会直接得到s已经定义的行为,而不会再去SpecialAccount中寻找。


16.3 Multiple Inheritance
多重继承

Lua中实现面向对象编程是有很多种途径的,上文中提到的使用 __index 元方法是一种便捷的方式。在不同的情况下需要选择不同的实现方式,在这里介绍的是一种能实现多重继承的方法。
这里也涉及到了使用__index 元方法,在该方法内使用一个函数。当table的元表的 __index 字段中有一个函数的时候,Lua都会调用该函数而不管有没有在该table中寻找到key。
多重继承的思想在于一个类可以有多个父类。因此我们就不能用类的方法来创建子类,而是定义一个函数来实现该功能--createClass,以父类作为参数来创建子类。这个函数创建一个table来代表新的类,然后设置元表的元方法__index 来实现多重继承。在这里有要注意的地方,类和父类的关系与类和实例的关系是有差异的,一个类不能同时成为其实例和其子类的元表
e.g.
--假定现在有两个类,之前的Account和现在的Named
Named = {}
function Named:getname()return self.name
end
function Named:setname(v)self.name = v
end--在plist这个table中寻找k
local function search(k,plist)for i = 1,#plist dolocal v = plist[i][k]if v then return v endend
endfunction createClass(…)local c = {}               --新的类local parents = { … }--从父类table中找到各个父类中的方法setmetatable(c,{ __index = function (t,k)return search(k,parents)end} )     --多重继承的技巧在于此处,__index 元方法是一个函数,该函数会从父类列表中寻找每个父类中的所有方法,这样就实现了多重继承--新的类成为其实例的元表c.__index = c--创建新的类的构造方法function c:new(o)o = o or {}setmetatable(o,c)return oendreturn c
end

现在我们就能创建一个多重继承的类了:
--多重继承,创建新的类
NamedAccount = createClass(Account,Named)

--创建和使用实例
account = NamedAccount:new{name = "abcd"}
print(account:getname())

上述的search函数一定程度上影响性能,以下是作者给的改进:
setmetatable(c,{ __index = function ( t,k )local  v = search(k,parents)t[k] = vreturn vend})

一种编程技巧,谨记!

16.4 Privacy
隐私

在已提到的对对象的设计中,并没有提供隐私机制。这是我们使用table来表现对象的结果,也是受影响与Lua本身排斥一些冗余、人为限制的功能。作者的建议是假如不想访问某些值,那么大可以不去访问就是。
Lua的目标是为开发者提供便利,提供多种技巧实现多数需求,尽管设计lua中的对象初衷是不提供隐私机制的,但是可以通过别的方法来实现这个需求——访问控制。这个用的比较少,但还是值得去了解和学习掌握的。
实现这个功能需求在于用两个table来表现对象:一个表示其状态,一个用来表示其操作行为。访问对象的时候通过第二个table进行访问,而对第一个table的设计也有一定的要求,该table并不是存储在别的table中,而是存储在该对象方法的closure中。以此重新设计Account
e.g.
function newAccount( initialBalance )local self = {balance = initialBalance}local withdraw = function ( v )self.balance = self.balance + vendlocal getBalance = function ( ... )return self.balanceendreturn{withdraw = withdraw,deposit = deposit,getBalance = getBalance}
end

在这里该函数首先创建了一个table用来存储内部对象的状态,存储至一个局部变量self。然后该函数内部创建了对象的一系列方法。最后函数创建并返回了另外一个对象,该对象内部存储了实际上要实现的方法的名字。返回的这个新的table应该相当于上文提到的第二个table。这里的核心点在于:这些方法没有使用冒号操作符得到self这个额外的默认参数,而是直接使用了。现在我们可以以一下方式创建新的对象并使用其方法:
e.g.
acc1 = newAccount(100.00)
acc1.withdraw(40.00)
print(acc1.getBalance())

利用这种方式创建的table,我们是没有办法直接访问原table的,只能通过newAccount里面的方法来访问。这样就实现来我们想要的隐私功能。


16.5 The Single-Method Approach
单例的实现

e.g.
print("The Single-Method Approach \n") 
function newObject( value )return function ( action,v )if action == "get" then return valueelseif action == "set" then value = velse error("invalid action")endend
endd = newObject(0)
print(d("get"))
d("set",10)
print(d("get"))


没有实例,直接通过对象本身访问对象实现的方法。

 

转载于:https://www.cnblogs.com/zhong-dev/p/4044574.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(转)AS3中的stage,this,root的区别

要了解这个问题就要先对flash中的显示对象结构有一个大概的了解: 第一级:舞台; 第二级:当前SWF; 第三级:各种容器及可视对象(如:文本框,位图……)&#xff1b…

面试官是怎样高效面试的(面试官的“套路”

大家好,我是若川。持续组织了6个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列最近正…

微服务负载均衡实现高可用_使用负载平衡实现大容量可用性

微服务负载均衡实现高可用Written by Yona Gidalevitz由Yona Gidalevitz撰写 Most users of the web are blissfully unaware of the sheer scale of the process responsible for bringing content across the Internet. There are literally miles of Internet between you …

Visual Studio 2008自带的Windows 系统使用的各种图标、光标和动画文件

1,Visual Studio 2008自带的1000多个 Windows 系统使用的各种图标、光标和动画文件 在Visual Studio 2008的安装目录下, /Microsoft Visual Studio 9.0/Common7/VS2008ImageLibrary/2052文件夹下面,有一个VS2008ImageLibrary.zip,…

Android中导入第三方jar

右键工程,Build path,Java build path,选择libraries在右边的按钮中点击“Add Library”选择“User library”,点击“下一步”点击“User librarys”按钮在出现的界面中点击“New..”按钮在弹出的界面中随便起一个名字,点击“确定”点击“Add jars”按钮…

19岁中专学历是怎么在广州找到前端工作的?

大家好,我是若川。持续组织了8个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列本文来…

tcp 接收端优雅的写法_如何更优雅地接收设计反馈

tcp 接收端优雅的写法重点 (Top highlight)It’s rare to meet a designer that doesn’t take pride in their work. After all, we are creatives and it’s what we love to do. Although design is teachable, there is a bit of natural skill and talent that comes into…

C++头文件一览表

传统 C   #include <assert.h>    //设定插入点   #include <ctype.h>//字符处理   #include <errno.h>//定义错误码   #include <float.h>//浮点数处理   #include <fstream.h>//文件输入&#xff0f;输出   #include &l…

一份 2.5k star 的《React 开发思想纲领》

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列翻译自…

asp.net生成jason给js

[WebMethod(EnableSession true)][ScriptMethod]public static object TEST(string testval){int type 0;string message "";int precent 0;return new { type type, message message, precent precent };} 转载于:https://www.cnblogs.com/bulege/archive/20…

文案写作软件_11种可改善网站用户体验的文案写作技术

文案写作软件Written by John Stevens约翰史蒂文斯 ( John Stevens)撰写 When we talk about user experience and your website, it is easy to get caught up in the site’s design and navigation options. While that is important, the words you place on the page are…

Table.Rows.Remove(dr)和Table.Delete()的区别

一个DataRow对象刚被创建之后其状态是Detached&#xff0c;是孤立的一个存在&#xff0c;所以建立了DataRow之后在DataRow中的单元填充了数据后还要通过DataTable.Rows.Add(DataRow)方法将此DataRow添加到DataTable&#xff0c;DataRow添加到DataTable后, 这个DataRow的状态就…

张小龙谈用户体验

原文&#xff1a;http://sd.csdn.net/a/20120510/2805483.html从Foxmail到腾讯“七星级产品”QQ邮箱&#xff0c;再到腾讯核武器级产品微信。在外界看来&#xff0c;腾讯副总裁、广州研发部总经理张小龙作风低调&#xff0c;很少接受正式的媒体采访。然而作为当今国内最优秀的产…

如何高效学习前端新知识,我推荐这些~

众所周知&#xff0c;关注公众号可以了解学习掌握技术方向&#xff0c;学习优质好文&#xff0c;落实到自己项目中。还可以结交圈内好友&#xff0c;让自己融入到积极上进的技术氛围&#xff0c;促进自己的技术提升。话不多说&#xff0c;推荐这些优质前端公众号前端之神100w阅…

web开发集成数字证书_每个数字设计师都应该知道的Web开发的七个原则

web开发集成数字证书A career path into digital design is often winding, meaning many practitioners come from adjacent fields as diverse as graphic design, web development, research, or even anthropology. As a result, two people working in a similar role may…

【转】CentOS 6.6 升级GCC G++ (当前最新版本为v6.1.0) (完整)

原文地址&#xff1a;https://www.cnblogs.com/lzpong/p/5755678.html 我这里是centos7 升级到gcc8.1&#xff0c;过程差不多&#xff0c;参考这篇文章&#xff0c;记录一下。 ---原文--- CentOS 6.6 升级GCC G (当前最新GCC/G版本为v6.1.0) 没有便捷方式, yum update.... yu…

Hadoop:mapreduce的splitsize和blocksize

参考&#xff1a; Hadoop MapReduce中如何处理跨行Block和UnputSplit https://stackoverflow.com/questions/17727468/hadoop-input-split-size-vs-block-size https://stackoverflow.com/questions/30549261/split-size-vs-block-size-in-hadoop转载于:https://www.cnblogs.co…

前端工程师生产环境 debugger 技巧

大家好&#xff0c;我是若川。持续组织了6个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列导言开…

bmp转jpg(使用libjpeg)

jpg压缩原理可以参考这篇文章http://hi.baidu.com/tiandsp/item/f5a2dcde6ef1405bd73aae41&#xff0c;我很早以前转的一篇文章。 没有使用libjpeg的压缩代码可以看看这篇文章http://hi.baidu.com/tiandsp/item/9b5843c58a3b4474cfd4f841&#xff0c;也是我很早以前转的。 这次…

figma设计_Figma与Adobe XD:我们如何选择下一个设计工具

figma设计The time came for changes and our design team started raising the topic again about how we should consider moving away from Sketch. This is not the first time this question came to mind, but this time seems like it was serious. Last summer we cons…