第16章 面向对象程序设计

Lua中的表不仅在某种意义上是一种对象。像对象一样,表也有状态(成员变量);也有与对象的值独立的本性,特别是拥有两个不同值的对象(table)代表两个不同的对象;一个对象在不同的时候也可以有不同的值,但他始终是一个对象;与对象类似,表的生命周期与其由什么创建、在哪创建没有关系。对象有他们的成员函数,表也有:

Account = {balance = 0}

function Account.withdraw (v)

    Account.balance = Account.balance - v

end

这个定义创建了一个新的函数,并且保存在Account对象的withdraw域内,下面我们可以这样调用:

Account.withdraw(100.00)

这种函数就是我们所谓的方法,然而,在一个函数内部使用全局变量名Account是一个不好的习惯。首先,这个函数只能在这个特殊的对象(译者:指Account)中使用;第二,即使对这个特殊的对象而言,这个函数也只有在对象被存储在特殊的变量(译者:指Account)中才可以使用。如果我们改变了这个对象的名字,函数withdraw将不能工作:

a = Account; Account = nil

a.withdraw(100.00)   -- ERROR!

这种行为违背了前面的对象应该有独立的生命周期的原则。

一个灵活的方法是:定义方法的时候带上一个额外的参数,来表示方法作用的对象。这个参数经常为self或者this

function Account.withdraw (self, v)

    self.balance = self.balance - v

end

现在,当我们调用这个方法的时候不需要指定他操作的对象了:

a1 = Account; Account = nil

...

a1.withdraw(a1, 100.00)     -- OK

使用self参数定义函数后,我们可以将这个函数用于多个对象上:

a2 = {balance=0, withdraw = Account.withdraw}

...

a2.withdraw(a2, 260.00)

self参数的使用是很多面向对象语言的要点。大多数OO语言将这种机制隐藏起来,这样程序员不必声明这个参数(虽然仍然可以在方法内使用这个参数)。Lua也提供了通过使用冒号操作符来隐藏这个参数的声明。我们可以重写上面的代码:

function Account:withdraw (v)

    self.balance = self.balance - v

end

调用方法如下:

a:withdraw(100.00)

冒号的效果相当于在函数定义和函数调用的时候,增加一个额外的隐藏参数。这种方式只是提供了一种方便的语法,实际上并没有什么新的内容。我们可以使用dot语法定义函数而用冒号语法调用函数,反之亦然,只要我们正确的处理好额外的参数:

Account = {

    balance=0,

    withdraw = function (self, v)

       self.balance = self.balance - v

    end

}

 

function Account:deposit (v)

    self.balance = self.balance + v

end

 

Account.deposit(Account, 200.00)

Account:withdraw(100.00)

现在我们的对象拥有一个标示符,一个状态和操作这个状态的方法。但他们依然缺少一个class系统,继承和隐藏。先解决第一个问题:我们如何才能创建拥有相似行为的多个对象呢?明确地说,我们怎样才能创建多个accounts?(译者:针对上面的对象Account而言)


相关链接:
lua程序设计目录 - 中国lua开发者 - lua论坛