Lua面向对象

自我总结一句话:警惕copy导致的数据冗余,和元表设置导致的深度索引
lua里面实现class机制,比较关键的地方就是class的继承机制,以及class实例化的过程。

class继承机制的关键是怎么让子类拥有父类的方法集:<br>
1.完全使用setmetatable()的方式实现,每继承一次,都把父类的方法集设置为子类方法集的metatable。这样做应该最符合class的继承的思想,尽可能的复用逻辑,而且可以做到动态更新父类的方法集后,所有子类都会焙蛳碛姓庀罡碌奶匦?比如满足某些特殊的动态更新需求)。但随着class继承的层次加深,会生成一个复杂的class方法集table(n层的metatable),毕竟metatable是有额外开销的,所以这个方法不一定是最完美的方案。<br>
2.将父类方法集copy到子类方法集来实现继承,即每当定义一个新的子类时,都将父类中方法集完整copy到子类方法集中。这种方法避免了使用metatable()带来的额外开销,但却造成了一些数据冗余(其实并不多),并丧失了父类更新子类也会自动更新的特性。<br>
3.方案2的改进版本(也就是云风这里使用的比较强悍的方式:P pf),即同样是采用copy父类方法集的方案,但却改进了copy的机制。将原本在class定义期执行的方法集copy工作转移到实例的运行期间,采用copy-on-use(等同于copy-on-write的设计思路)的方式,在子类实例用到父类的某个方法时,才将其copy到子类的方法集中。由于这种copy只发生一次,而且不见得子类会用到父类方法集中的所有内容(事实如此),所以这个方案相对于方案2来说减少了冗余数据,但却几乎没有增加任何额外开销。

class实例化关键是实例如何享有class的方法集:<br>
1.最烂的方式,方法集copy,即class实例化时,将class的方法集直接copy给实例的数据table。这样的好处就是每个实例创建后,外界除非直接操作实例的数据table,否则其它行为都不会影响到这个实例的所有属性和特征(也许可以满足某些特殊的需求吧),同时也省掉了一次metatable的查找开销。缺点很明显,实例化过程低效,而且产生大量的冗余信息(或者这里也采用copy-on-use的思想? :p)。<br>
2.采用将class方法集设置为实例的metatable的方式,使实例享有class的方法集(这要求实例的数据类型必须可以拥有自己的metatable,即只能是table或userdata)。这个方案更优雅一些,而且符合class的共享思想并且实例化开销很小,应该是实现实例化的最佳方案了。在实现子类的初始化函数时,一般的思路都是先生成一个父类的实例,再强制将当前子类的方法集设置为这个实例的metatable。

目前我们采用的class机制就是上述的两个2号方案(考虑更新到云风的3号方案),自己实现了两个接口class_define()、class_inherit(),其实完成的功能等同于以上代码中的class()。还是很pf lua的作者,估计在设计lua时就考虑到了面向对象的实现问题,很class的多关键机制(如隐式self参数、metatable机制)都已实现,这为自己实现class机制提供了强有力的支持。加上脚本的弱数据类型特性,只要思路清晰,在C++中可以实现的class机制lua中基本都能实现一个翻版,也许下个版本的lua可能会显示支持class:)

https://blog.codingnow.com/2006/06/oo_lua.html

posted @ 2020-04-18 08:02  钢与铁  阅读(304)  评论(0编辑  收藏  举报