niubo_
2010-06-28 00:55:53
[i=s] 本帖最后由 niubo_ 于 2010-6-28 01:08 编辑 [/i]
lua中的面向对象是由table来模拟的。面向对象的重要思想就是继承,这一点可以由metatable来实现,不过有一点是pil没有详细区别,就是类继承和原型继承。
基本上,静态语言中使用的都是类继承,先定义一个类,另一个类可以继承这个类……但是对于动态语言来说,定义的不是类而是对象,所以可以有一个对象继承另一个对象的“原型继承”。
对于类概念,可以想象成一张图纸,上面描述了一个对象应具有什么状态和行为,图纸画好了就可以拿去“生产”对象。而继承则可以理解成一张张半透明的图纸,可以在一张画好的图纸上蒙上另一张图纸,只需在画上下面那张图纸上没有的部分就可以了。当然,在生产对象的时候要把所有图纸都拿过去才可以。
原型继承呢,就可以想象成一个铝锅,以这个铝锅作原型加工一个模子,用这个模子铸口新锅出来。这口新锅和原型是一模一样的,但是之后还可以对它再加工,动态语言在运行时给对象添加属性和方法没有任何问题。
lua以原型继承的机制实现面向对象是比较简单的,现在举个例子:[code]
Object = {
name = "Object",
_init = function(self) end
}
mt = {}
new = function(o, parent)
-- o为要创建的对象,parent是其父类
local parent = parent or Object
local o = o or {} -- 如果没有定义,就是一个空的类
mt.__index = parent
setmetatable(o, mt)
-- 如果初始化方法已定义则执行初始化方法
if o._init ~= nil then
o:_init()
end
return o
end
[/code]核心内容是一个new函数,这个函数负责打造一个新的对象出来,如果给定对象的定义式(实际上是table的定义式)就用这个table生成对象,否则就给一个空table;如果给定了原型对象就用它做原型,否则就拿Object做原型。
另外如果定义了初始化方法,在创建出对象后执行初始化方法。在初始化方法中可以给这个对象添加属性和方法。
写个小例子运行一下:[code]
mother = new{
_init = function(self)
self.name = "老妈"
self.money = 10000
end,
consum = function(self,amount)
print(self.name .. "花了" .. amount .. "元")
self.money = self.money - amount
end,
speak = function(self)
local words = {"我是", self.name, ",我有",self.money,"元"}
print(table.concat(words))
end
}
son = new({
_init = function(self)
self.name = "儿子"
end
}, mother)
mother:speak()
son:speak()
mother:consum(100)
mother:speak()
son:consum(500)
son:speak()
mother:speak()
[/code]运行结果:
我是老妈,我有10000元
我是儿子,我有10000元
老妈花了100元
我是老妈,我有9900元
儿子花了500元
我是儿子,我有9400元
我是老妈,我有9900元
这里定义了一个老妈一个儿子,儿子开始只有自己的名字,说话是从老妈那学的,花钱是从老妈那学的,当然钱也是老妈那拿的。
首先,老妈说自己有一万块,儿子说我有一万块。其实这时儿子还没有钱的概念,理所当然的认为老妈的钱就是自己的钱。老妈花了一百块,老妈说我现在还有九千九,儿子也开始花钱,花了五百(这个败家子),儿子说我还有九千四,但是老妈说我还有九千九……等等,儿子不是花老妈的钱吗?那为什么老妈的钱还是九千九呢?
问题出在这里:self.money = self.money - amount 引用money时儿子没有钱,所以引用到的是老妈的钱,但是计算之后又赋值,这相当于定义,从这一刻,儿子有钱了,金额是老妈剩下的钱减去自己刚刚花掉那些。虽然不合常理,但是对程序来说仅仅是一次普通的赋值而已。
以Java为例看看在面向对象的静态语言中类似的情况是怎样的。Java中创建一个对象,会隐式创建继承链上的所有对象,但那些对象都是隐含的,我们不能直接去操作。这时老妈就完全成了儿子的钱袋,即使儿子的钱和花钱的行为都是从老妈那继承的,但从外界看来这都是儿子自己的属性和行为,在儿子身后的老妈不可能自己花钱。而且Java没有在运行时动态给对象添加属性这种事,所以只要在儿子的定义中没有自己的钱,则注定永远花老妈的钱。
所以这种“原型”继承比较理想的使用方法是子类继承父类的方法,但是要定义自己的属性。这是很有道理的:“用祖先的汉语表达自己的思想”嘛。这样也符合其他一些面向对象中对对象的处理方法:多个对象拥有各自的对象却共有一套方法。
一般常见所谓Class库都是基于这种方式,可能还加入多重继承和其他一些机制。使用时先定义一个父类,在执行时先创建一个子类,初始化时添加相应的属性,然后调用方法完成操作……
“原型继承”实质上师对象继承对象,跟“类”就没什么关系了。不过想实现传统的面向对象机制需要考虑这些问题:
要分别用table模拟“类”和“对象”;要有定义类的方法,还有“实例化”对象的方法等等,这个现在我只发现有一个叫做“MiddleClass”的库实现了这种机制,有兴趣可以研究一下:[url]http://love2d.org/wiki/MiddleClass[/url]
说句题外话,love2d这个游戏引擎貌似还不错……
a8816003
2010-06-28 01:00:43
略懂略懂~~~
『兔寳貝』
2010-06-28 07:41:49
如果继续运算.
儿子是用现有的9400减去.还是变成妈妈的再减去?
wz20084596
2010-06-28 09:46:16
⊙﹏⊙b汗 还是看得.......
白枫
2010-06-28 10:13:36
牛叔威武,lua太猥琐了
niubo_
2010-06-28 18:32:58
[quote]如果继续运算.
儿子是用现有的9400减去.还是变成妈妈的再减去?
[size=2][color=#999999]『兔寳貝』 发表于 2010-6-28 07:41[/color] [url=http://www.yayabo.cn/redirect.php?goto=findpost&pid=48520&ptid=5225][img]http://www.yayabo.cn/images/common/back.gif[/img][/url][/size][/quote]
这个当然是从儿子有了钱的概念(定义)之后就和老妈的钱没有任何关系了,以后再花就是自己的钱了。
『兔寳貝』
2010-06-28 22:09:02
那这样不就是出错了麽?
钱无中生有了.