类(Class)

本文涉及的产品
语种识别,语种识别 100万字符
文档翻译,文档翻译 1千页
图片翻译,图片翻译 100张
简介: 类(Class)

截止至目前,我们的对象具有了标识状态和对状态进行的操作,但还缺乏类体系继承私有性。让我们先来解决第一个问题,即应该如何创建多个具有类似行为的对象。更具体地说,我们应该如何创建过个银行账户呢?


大多数面向对象语言提供了的概念,类在对象的创建中扮演了模板的作用。在这些语言中,每个对象都是某个特定类的实例。 Lua 语言中没有类的概念,虽然元表的概念在某种程度上与类的概念相似,但是把元表当做类使用在后续会比较麻烦。相反,我们可以参考基于原型的语言中的一些做法来在 Lua 语言中模拟类,例如 JavaScript 语言。在这些语言中,对象不属于类。相反,每个对象可以有一个原型prototype )。原型也是一种普通的对象,当对象(类的实例)遇到一个未知操作时会首先在原型中查找。要在这种语言中表示一个类,我们只需要创建一个专门被用作其他对象(类的实例)的原型对象即可。类和原型都是一种组织多个对象间共享行为的方式。


Lua 语言中,我们可以使用__index 元方法中所述的继承的思想来实现原型。更准确地说,如果有两个对象 AB ,要让 B 成为 A 的一个原型,只需要:

setmetatable(A,{__index = B})


在此之后, A 就会在 B 中查找所有它没有的操作。如果把 B 看作对象 A 的类,则只不过是术语上的一个变化。


让我们回到之前银行账号的示例,为了创建其他与 Account 行为类似的账号,我们可以使用 __index 元方法让这些新对象从 Account继承这些操作。

local mt = { __index = Account }
function Account.new(o)
  o = o or {}
  setmetatable(o, mt)
  return o
end


在这段代码执行后,当我们创建一个新账户并调用新账户的一个方法时会发生什么呢?

a = Account.new{balance=0}
a:deposit(100.00)


当我们创建一个新账户 a 时, a 会将 mt 作为其元表。当调用 a:deposit(100.00) 时,实际上调用的是 a.deposit(a, 100.00) ,冒号只不过是一个语法糖。不过, Lua 语言无法在表 a 中找到字段 "deposit" ,所以他会在元表的 __index 中搜索。此时的情况大致如下:

getmetatable(a).__index.deposit(a, 100.00)


a 的元表是 mt ,而 mt.__indexAccoun t。因此,上述表达式等价于:

Account.deposit(a, 100.00)


即, Lua 语言调用了原来的 deposit 函数,传入了 a 作为 self 参数。因此,新账户 aAccount 继承了函数 deposit 。同样,它还从 Account 继承了所有的字段。


对于这种模式,我们可以进行以下两个小改进:

  1. 不创建扮演元表角色的新表而是把表Account直接用作元表
  2. new方法也使用冒号语法


加入上述两个改进之后,方法 new 会变成:

function Account:new (o)
  o = o or {}
  self.__index = self
  setmetatable(o, self)
  return o
end


现在,当我们调用 Account.new() 时,隐藏的参数 self 得到的实参是 Account , Account.__index 等于 Account ,并且 Account 被用作新对象的元表。可能看上去第二种修改(冒号语法)并没有得到大大的好处,但实际上当我们引入类的继承时,使用 self 的优点就会很明显了。


继承不仅可以用作方法,还可以用作于其他在新账户中没有的字段。因此,一个类不仅可以提供方法,还可以为实例中的字段提供常量和默认值。请注意,在第一版的 Account 的定义中,有一个 balance 字段的值是 0 。因此,如果在创建新账户时没有提供初始的余额,那么余额就会继承这个默认值:

b = Account:new()
print(b.balance)          --> 0


当在 b 上调用 deposit 方法时,由于 self 就是 b ,所以等价于:

b.balance = b.balance + v


表达式 b.balance 求值后等于零,且该方法给 b.balance 赋了初始的金额。由于此时b有了它自己的 balance 字段,因此后续对 b.balance 的访问就不会再涉及元方法了。

目录
相关文章
|
2月前
|
C++
【C++基础】类class
【C++基础】类class
18 1
|
2月前
|
Java
java-基础-Interface、abstract类、Static class 、non static class的区别
【4月更文挑战第5天】Java中的接口、抽象类、静态类和非静态类各具特色:接口仅含抽象方法和常量,用于定义行为规范;抽象类可包含抽象和非抽象方法,提供部分实现,支持多继承;静态内部类不依赖外部类实例,可独立存在,访问外部类的静态成员;非静态内部类持有关联外部类引用,能访问其所有成员。这些机制根据设计需求和场景选择使用。
21 6
|
2月前
|
Java API
Class 类
Class 类
17 1
|
2月前
|
Java
获取 Class 对象
获取 Class 对象
16 1
|
11月前
|
缓存 Java
Java 反射之Class类的理解以及获取Class的实例
Java 反射之Class类的理解以及获取Class的实例
44 0
|
JavaScript 程序员
Class-总结class的基本用法和两个注意点
一、注意点一:class关键字区间使用 二、注意点二:Class关键字内部函数
|
Java
Class类
Class类
94 0