最近一直没在偷懒,在收集各种开源项目中OOP的实现方案。关于其中的理解,因为给新人指导,就要求自己能够很好的理解,并讲解出来。教会也是给对于知识理解的更高阶段。
一、实现OOP
- 核心是Metatable和__index方法
- 理解OOP中类继承多重继承
可见我上一篇文章Lua的metatable和Lua的面向对象实现
二、lua 的作者推荐了一种方案来实现 OO
|
|
SimpleLuaClasses
这个实现方式很特殊,不是那么直白的使用 metatable 去实现,而是通过 debug API 实现的。熟悉 lua 的朋友可能看得出来这个类似与 setfenv,因为只有 lua 5.1 才有 setfenv 和 getfenv,这个是 lua5.3 上的实现。关于 5.3 上的实现可以参考
https://leafo.net/guides/setfenv-in-lua52-and-above.html
三、云风实现的Lua面向对象
|
|
以上是基本的 class 定义的语法,完全兼容 lua 的编程习惯。增加了一个叫做 ctor 的词,作为构造函数的名字。
https://blog.codingnow.com/cloud/LuaOO
四、cocos2dx-lua 中的 class 实现
|
|
五、xlua-framework 中的 class 实现
|
|
xlua-framework
xlua-framework/Assets/LuaScripts/Framework/Common/BaseClass.lua
六、2种实现方式的总结
- 1、使用metatable的__index域实现,实现的时候需要利用的lua语言的一些特性才可以实现
- 优点:
- 1、由于子类的很多数据和方法都是共用了父类的,用到父类的数据和方法的时候,只是在使用的时候才直接调用父类的方法和数据,这样可以减少程序内存的消耗,更主要的是,父类在运行期的修改是会影响到子类的;
- 2、充分利用了lua语言的特性,父类的方法和数据的访问是解析器来做的,所以效率上的开销还是比较小的;
- 缺点:
- 1、如果父类中有一个数据是一个引用的时候(如table)的时候,就会出现在一个子类中操作这个table会改变其他子类的情况,造数据的不一致,所以应该尽量避免这种类的创建,如果有这样的需求的话,就需要对inherit和new函数进行一些特殊的操作,简单来说就是加一个init函数,将所有这类的数据都显示的创建一下。
- 2、由于每次取操作都需要在metatable中取,所以,每次就会增加一层继承,就增加一个函数调用的开销,虽然是由解析器来做的,但是如果层次多了的话,还
- 优点:
- 2、使用table拷贝的方式实现,实现的时候利用的lua的技术为:
- 优点:
- 1、父类中的数据是全部拷贝到子类中的,所以,不存在数据不一致的情况;
- 2、所有的函数调用和数据调用都是直接调用每个实例的,不需要到父类中查找;
- 缺点:
- 1、全部数据的copy,在创建的时候就会增加一个table copy的过程,影响效率;
- 2、全部数据和方法都是在创建的时候拷贝一份的,会增加很多的内存消耗,而且如果在运行期改变了父类,并不能改变子类;
- 优点:
七、最后的总结
结合这两种方式的有缺点,从一个面向对象的角度来说,第一种方式更加适合实现面向对象的特性,第二种方式对面向对象的模拟就牵强一些(缺点2),但是从使用的角度来说,因为在访问数据和方法速度上,第二种方式还是有优势的,所以,在具体的使用的时候,可以灵活一下使用,将两者结合一下。
比如说,对于客户端这边来说,类在开始创建好了以后就一般不需要修改了,而且子类一般都是需要父类的所有的方法和数据的,所有我们就可以使用第二种方式,而生成对象实例的时候,对象的实例一般都不会调用类的所有的方法,而且用完了这个实例,就会销毁的,所以,我们这里就可以采用第一种方式。
基于以上的想法进行改进,这样用于作为所有界面的基类
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849function class(classname,super)local superType = type(super)local clsif superType ~= "function" and superType ~= "table" thensuperType = nilsuper = nilendif superType == "function" or (super and super.__ctype == 1) thencls = {}if superType == "table" thenfor k,v in pairs(super) do cls[k] = v endcls.__create = super.__createcls.super = superelsecls.__create = superendcls.ctor = function(...) endcls.__cname = classnamecls.__ctype = 1function cls.New(...)local ins = cls.__create(...)for k,v in pairs(cls) do ins[k] = v endins.class = clsins:ctor(...)return insendelseif super thencls = clone(super) --与cocos2dx-lua 中的 class 实现不同之处cls.super = superelsecls = {ctor = function(...) end}endcls.__cname = classnamecls.__ctype = 2-- luatablecls.__index = clsfunction cls.New(...)local ins = setmetatable({},cls)ins.class = clsins:ctor(...)return insendendreturn cls所有单例的实现就用第五种的实现
附
- 感谢这篇文章的作者Lua class 的几种实现,不然我这篇文章可能要拖一段时间
- http://www.lua.org/pil/16.html
- lua实现面向对象的特性
- 感谢Misaka Mikoto[https://www.zhihu.com/people/jasonfeeling]在Lua上解答了我很多问题,给予方向上的指点