本第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于更高版本,但存在一些差异。
第四版针对 Lua 5.3,可在 Amazon 及其他书店购买。
通过购买本书,您也为 支持 Lua 项目 提供了帮助。
![]() |
Lua编程 | ![]() |
| 第二部分 表和对象 第十六章 面向对象编程 |
许多人认为隐私是面向对象语言不可或缺的一部分;每个对象的状态都应该是其内部事务。在某些面向对象语言中,例如 C++ 和 Java,您可以控制对象字段(也称为实例变量)或方法是否在对象外部可见。其他语言,例如 Smalltalk,则使所有变量私有,所有方法公有。第一种面向对象语言 Simula 没有提供任何形式的保护。
我们之前展示的 Lua 中对象的主要设计没有提供隐私机制。部分原因是我们使用通用结构(表)来表示对象。但这也反映了 Lua 背后的一些基本设计决策。Lua 不旨在构建需要许多程序员长期参与的庞大程序。恰恰相反,Lua 旨在构建小型到中型程序,通常是大型系统的一部分,通常由一名或几名程序员,甚至是非程序员开发。因此,Lua 避免了过多的冗余和人为限制。如果您不想访问对象内部的某些内容,只需不要这样做。
然而,Lua 的另一个目标是灵活性,为程序员提供元机制,通过这些机制她可以模拟许多不同的机制。虽然 Lua 中对象的基本设计不提供隐私机制,但我们可以以不同的方式实现对象,以实现访问控制。虽然这种实现不常使用,但了解它是有益的,因为它既探索了 Lua 的一些有趣角落,又可以作为解决其他问题的好方案。
这种替代设计的基本思想是通过两个表来表示每个对象:一个用于其状态;另一个用于其操作,或其接口。对象本身通过第二个表访问,即通过构成其接口的操作。为了避免未经授权的访问,表示对象状态的表不存储在另一个表的字段中;相反,它只存储在方法的闭包中。例如,要用这种设计表示我们的银行账户,我们可以运行以下工厂函数来创建新对象
function newAccount (initialBalance)
local self = {balance = initialBalance}
local withdraw = function (v)
self.balance = self.balance - v
end
local deposit = function (v)
self.balance = self.balance + v
end
local getBalance = function () return self.balance end
return {
withdraw = withdraw,
deposit = deposit,
getBalance = getBalance
}
end
首先,函数创建一个表来保存内部对象状态并将其存储在局部变量 self 中。然后,函数为对象的每个方法创建闭包(即嵌套函数的实例)。最后,函数创建并返回外部对象,该对象将方法名映射到实际的方法实现。这里的关键是这些方法不会将 self 作为额外参数;相反,它们直接访问 self。由于没有额外参数,我们不使用冒号语法来操作此类对象。方法的调用就像任何其他函数一样 acc1 = newAccount(100.00)
acc1.withdraw(40.00)
print(acc1.getBalance()) --> 60
这种设计为存储在 self 表中的任何内容提供了完全的隐私。在 newAccount 返回后,无法直接访问该表。我们只能通过 newAccount 内部创建的函数访问它。尽管我们的示例只将一个实例变量放入私有表中,但我们可以将对象的所有私有部分存储在该表中。我们还可以定义私有方法:它们类似于公共方法,但我们不将它们放入接口中。例如,我们的账户可能会为余额超过某个限制的用户提供 10% 的额外信用,但我们不希望用户访问此计算的详细信息。我们可以按如下方式实现
function newAccount (initialBalance)
local self = {
balance = initialBalance,
LIM = 10000.00,
}
local extra = function ()
if self.balance > self.LIM then
return self.balance*0.10
else
return 0
end
end
local getBalance = function ()
return self.balance + extra()
end
...
同样,任何用户都无法直接访问 extra 函数。| 版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 | ![]() |