AceOO-2.0 指南
译者:simonw
原文发表于: AceOO-2.0_Tutorial
Contents
注释: 以下的示例我使用了一个自定义的打印函数.
1 function print(text)
2 DEFAULT_CHAT_FRAME:AddMessage(tostring(text))
3 end
开始
为了访问AceOO-2.0, 你需要将AceOO-2.0 library 加入到你的项目中并且在TOC中这样写:
1 AceOO-2.0\AceOO-2.0.lua
在lua文件中你需要加入:
1 local AceOO = AceLibrary("AceOO-2.0")
获得一个AceOO-2.0的local reference.
声明新类
1 local Chicken = AceOO.Class()
这创建了一个没有额外方法的Chicken空白类, 衍生自Class.
获取类的实例
1 local kingRooster = Chicken:new()
king rooster 是Chicken类的一个实例. 我们可以调用 :new() 多次来创建多个不同的Chicken类的实例.
添加 :ToString()
通过类的引用来打印出类型信息.
1 function Chicken:ToString()
2 return "Chicken"
3 end
4 -- So now this happens:
5
6 print(Chicken) -- "Chicken"
7 print(kingRooster) -- "<Chicken instance>"
8 object:ToString() -- will be called whenever tostring(object) is called
添加方法
创建一个猫的类, 做2件事情: 爱抚(pet) 和 泼水(spray with water). (猫不喜欢被泼水.)
1 local AceOO = AceLibrary("AceOO-2.0")
2
3 local Cat = AceOO.Class()
4
5 Cat.prototype.happiness = "Neutral"
6
7 function Cat.prototype:Pet()
8 if self.happiness == "Unhappy" then
9 self.happiness = "Neutral"
10 else
11 self.happiness = "Happy"
12 end
13 end
14
15 function Cat.prototype:SprayWithWater()
16 if self.happiness == "Happy" then
17 self.happiness = "Neutral"
18 else
19 self.happiness = "Unhappy"
20 end
21 end
22
23 local reginald = Cat:new() -- 一只猫
24 local fluffers = Cat:new() -- 另一只猫
25
26 -- reginald is cute. fluffers was bad.
27 reginald:Pet()
28 fluffers:SprayWithWater()
29 print(string.format("%s - %s", reginald.happiness, fluffers.happiness)) -- "Happy - Unhappy"
尽快例子有点傻但却是做了个很好的示范. 两只不同的猫有不同的特征各自独立互相不依赖.
你可能对 .prototype 有点奇怪. 所有的实例均继承于此, 而不是继承自Class. 稍后会详细解释.
1 print(AceOO.inherits(reginald, Cat)) -- true
2 print(AceOO.inherits(fluffers, Cat)) -- true
3 print(reginald ~= fluffers) -- true
这里展示了reginald 和 fluffers 都是猫但不是同一只猫.
继承
类可以从其他类继承, 当前所有的类均继承自标准的Class. 这里将展现一个类继承自一个用户定义的类.
1 local AceOO = AceLibrary("AceOO-2.0")
2
3 local Dog = AceOO.Class()
4 Dog.virtual = true -- 这个意思是禁止实例化. (即不能调用 :new())
5
6 function Dog.prototype:Bark()
7 -- 如果子类没有实现这个方法将引发一个异常.
8 error("`Bark' not implemented", 2)
9 end
10
11 local Chihuahua = AceOO.Class(Dog) -- 新类, 继承自Dog类.
12
13 function Chihuahua.prototype:Bark()
14 return "Arf! Arf! Arf!"
15 end
16
17 local Bulldog = AceOO.Class(Dog) -- 新类, 继承自Dog类.
18
19 function Bulldog.prototype:Bark()
20 return "Wuff! *slobber*"
21 end
22
23 local Sheepdog = AceOO.Class(Dog) -- 新类, 继承自Dog类.
24
25 function Sheepdog.prototype:Bark()
26 return "Ruff."
27 end
28
29 local killer = Chihuahua:new()
30 local muffin = Bulldog:new()
31 local leopold = Sheepdog:new()
32
33 print(killer:Bark()) -- "Arf! Arf! Arf!"
34 print(muffin:Bark()) -- "Wuff! *slobber*"
35 print(leopold:Bark()) -- "Ruff."
这些都是狗的类型但他们的叫法均不同, 因为是不同类型的狗类.
构造函数
1 local AceOO = AceLibrary("AceOO-2.0")
2
3 local Pig = AceOO.Class()
4
5 function Pig.prototype:init(name)
6 Pig.super.prototype.init(self) -- 非常重要, 缺少会报错.
7 self.name = name
8 end
9
10 function Pig.prototype:tostring()
11 return self.name
12 end
13
14 local bacon = Pig:new("Bacon") -- new pig named Bacon
15
16 print(bacon) -- should print "Bacon", cause that's its name.
这个 :init(...) 方法在 AceOO-2.0 中代表构造方法. 在其中, 第一行必须先调用父类的 init 方法, 可以任意传递适当的参数给他. 如果你传递了参数, 父类的构造函数将不会被自动调用.
当类实例化的时候构造函数将被调用. (调用 :new(...)的时候). :new(...) 所有的参数(最多20个)将被传递到 :init(...)
静态方法 vs. 实例方法
静态方法是本类所特定的, 子类并不继承他们. 实例方法属于类的实例(即对象)子类将继承他们.
1 local AceOO = AceLibrary("AceOO-2.0")
2
3 local Box = AceOO.Class()
4 Box.numBoxes = 0
5
6 function Box:GetNumBoxes()
7 return self.numBoxes
8 end
9
10 function Box.prototype:init()
11 Box.super.prototype.init(self)
12
13 Box.numBoxes = Box.numBoxes + 1
14 end
15
16 function Box.prototype:Shake()
17 print("You hear something crunch")
18 end
19
20 local blueBox = Box:new()
21 local redBox = Box:new()
22 print(Box:GetNumBoxes()) -- 2
23
24 local Crate = AceOO.Class(Box)
25 Crate.numCrates = 0
26
27 function Crate:GetNumCrates()
28 return Crate.numCrates
29 end
30
31 function Crate.prototype:init()
32 Crate.super.prototype.init(self) -- 调用 Box 的构造函数
33
34 Crate.numCrates = Crate.numCrates + 1
35 end
36
37 local greenCrate = Crate:new()
38 local blackCrate = Crate:new()
39 print(Box:GetNumBoxes()) -- 4
40 print(Crate:GetNumCrates()) -- 2
41 -- 注意: Crate 没有 a :GetNumBoxes() 这样的方法
42 blackCrate:Shake() -- You hear something crunch.
所有的 crates 都是 boxes, 总共有 4个 boxes. 因为 crates 是 boxes 所以你也可以shake crates. 静态方法class本身中声明, 而实例方法需要在 class 的 prototype 中声明.
接口
接口定义了对象或类的特定契约.
1 local AceOO = AceLibrary("AceOO-2.0")
2
3 local ISpeakable = AceOO.Interface { Speak = "function" }
4 -- 声明一个只包含 Speak 方法的接口.
5
6 local Dog = AceOO.Class(ISpeakable)
7
8 function Dog.prototype:Speak()
9 return "Bark!"
10 end
11
12 local Cat = AceOO.Class(ISpeakable)
13
14 function Cat.prototype:Speak()
15 return "Meow!"
16 end
17
18 local fluffy = Dog:new()
19 local mrPants = Cat:new()
20 assert(fluffy:Speak() == "Bark!")
21 assert(mrPants:Speak() == "Meow!")
22
23 print(not AceOO.inherits(Cat, Dog)) -- true
24 print(not AceOO.inherits(Dog, Cat)) -- true
25 print(AceOO.inherits(Cat, ISpeakable)) -- true
26 print(AceOO.inherits(Dog, ISpeakable)) -- true
27
28 -- 如果 Cat 或 Dog 没有实现 speak 方法, 将会抛出一个异常.
29 -- 一个好的建议是将所有的数据定义放在你的接口定义前, 如下.
30
31 local AceOO = AceLibrary("AceOO-2.0")
32
33 local Dog = AceOO.Class()
34
35 Dog.prototype.happiness = 5
36
37 function Dog:Hug()
38 self.happiness = self.happiness + 1
39 end
40
41 local Cat = AceOO.Class()
42
43 function Cat:Hug()
44 print("Purr")
45 end
46
47 local muffin = Dog:new()
48 local mephistophiles = Cat:new()
49 muffin:Hug()
50 mephistophiles:Hug() -- "Purr"
51
52 print(not AceOO.inherits(Cat, Dog)) -- true
53 print(not AceOO.inherits(Dog, Cat)) -- true
54
55 local IHuggable = AceOO.Interface { Hug = "function" }
56 -- 声明一个新接口, 包含 Hug 方法.
57
58 print(AceOO.inherits(Cat, IHuggable)) -- true
59 print(AceOO.inherits(Dog, IHuggable)) -- true
Cat 和 Dog 均继承自 IHuggable 接口, 因此上面的测试通过.
Mixins
Mixins(混入)提供了一种多继承的方式, 同时没有一些多继承所带来的问题, 如菱形继承(译注, 是指在多继承树中包含了同名的祖先而引发的问题).
1 local AceOO = AceLibrary("AceOO-2.0")
2
3 local Artist = AceOO.Mixin { "Paint", "Sculpt" } -- Artist 混入了 Paint 和 Sculpt 方法.
4
5 function Artist:Paint()
6 print(string.format("%s paints a beautiful picture", self))
7 end
8
9 function Artist:Sculpt()
10 print(string.format("%s sculpts a delightful statue", self))
11 end
12
13 local Scientist = AceOO.Mixin { "Think" } -- Scientist 混入了Think 方法
14
15 function Scientist:Think()
16 print(string.format("%s thinks about life", self))
17 end
18
19 local Inventor = AceOO.Mixin { "Invent" } -- Inventor 混入了 Invent 方法
20
21 function Inventor:Invent()
22 print(string.format("%s invents a cool device", self))
23 end
24
25 local GreatPerson = AceOO.Class(Artist, Scientist, Inventor) -- 一个伟人将具备Artist, Scientist, Inventor 的所有的优良品德.
26
27 function GreatPerson.prototype:init(name)
28 GreatPerson.super.prototype.init(self)
29 self.name = name
30 end
31
32 function GreatPerson.prototype:ToString()
33 return self.name
34 end
35
36 local daVinci = GreatPerson:new("Leonardo da Vinci")
37 daVinci:Think()
38 daVinci:Invent()
39 daVinci:Paint()
40 daVinci:Sculpt()
daVinci(达芬奇)是个多才多艺的人
Metamethods
如果你声明了一个使用了以下名字的方法, 将会对应lua的metamethod(元方法,基本操作符).
1 --这里是一些lua metamethod:
2 self:ToString() -- tostring(self)
3 self:Add(other) -- self + other
4 self:Subtract(other) -- self - other
5 self:Multiply(other) -- self * other
6 self:Divide(other) -- self / other
7 self:Exponent(other) -- self ^ other
8 self:Concatenate(other) -- self .. other
9 self:UnaryNegation() -- -self
10 self:Equals(other) -- self == other
11 self:IsLessThan(other) -- self < other
12 self:IsLessThanOrEqualTo(other) -- self <= other
13 self:CompareTo(other) -- (self.value - other.value)
没有:IsGreaterThan(other)或:IsGreaterThanOrEqualTo(other),因为 not (self < other) 就是 self >= other;not (self <= other) 就是 self > other;
因为not (other < self) 就是 self <= other,所以假如有了:IsLessThan(other),:IsLessThanOrEqualTo(other)也是可选的;
假如有:CompareTo(other),它就可以替代:Equals(other), :IsLessThan(other)和:IsLessThanOrEqualTo(other)。self:CompareTo(other) == 0意味着self == other; < 0 则 self < other, >0 则 self > other;
1 local AceOO = AceLibrary("AceOO-2.0")
2
3 local Number = AceOO.Class()
4
5 function Number.prototype:init(value)
6 Number.super.prototype.init(self)
7
8 self.value = value
9 end
10
11 function Number.prototype:ToString()
12 return "Number(" .. self.value .. ")"
13 end
14
15 function Number.prototype:Add(other)
16 return Number:new(self.value + other.value)
17 end
18
19 function Number.prototype:Equals(other)
20 return self.value == other.value
21 end
22
23 print(Number:new(1) + Number:new(2)) -- "Number(3)"


