Login

AceOO-2.0 指南

译者:simonw
原文发表于: AceOO-2.0_Tutorial

注释: 以下的示例我使用了一个自定义的打印函数.

   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)"


ACE文档资料类, simonw

AceOO2.0指南 (last edited 2008-06-13 05:53:28 by 月色狼影)