面向对象编程 #

一、面向对象基础 #

1.1 Lua 中的对象 #

Lua 没有内置的类系统,但可以通过表和元表实现面向对象:

lua
-- 对象是表
local person = {
    name = "Alice",
    age = 30,
    
    greet = function(self)
        print("Hello, I'm " .. self.name)
    end
}

person:greet()  -- Hello, I'm Alice

1.2 冒号语法 #

lua
-- 冒号定义方法(自动添加 self 参数)
local person = {
    name = "Alice",
    age = 30
}

function person:greet()
    print("Hello, I'm " .. self.name)
end

-- 等价于
function person.greet(self)
    print("Hello, I'm " .. self.name)
end

-- 调用
person:greet()      -- 冒号调用
person.greet(person) -- 点调用

二、实现类 #

2.1 基本类 #

lua
local Person = {}
Person.__index = Person

-- 构造函数
function Person:new(name, age)
    local instance = setmetatable({}, self)
    instance.name = name
    instance.age = age
    return instance
end

-- 方法
function Person:greet()
    print(string.format("Hello, I'm %s, %d years old.", self.name, self.age))
end

function Person:get_age()
    return self.age
end

-- 使用
local alice = Person:new("Alice", 30)
local bob = Person:new("Bob", 25)

alice:greet()  -- Hello, I'm Alice, 30 years old.
bob:greet()    -- Hello, I'm Bob, 25 years old.

2.2 带初始化方法的类 #

lua
local Person = {}
Person.__index = Person

function Person:new(name, age)
    local instance = setmetatable({}, self)
    instance:init(name, age)
    return instance
end

function Person:init(name, age)
    self.name = name
    self.age = age
end

function Person:greet()
    print("Hello, I'm " .. self.name)
end

2.3 类属性和方法 #

lua
local Counter = {}
Counter.__index = Counter

-- 类属性(静态属性)
Counter.count = 0

function Counter:new()
    Counter.count = Counter.count + 1
    return setmetatable({id = Counter.count}, self)
end

-- 实例方法
function Counter:get_id()
    return self.id
end

-- 类方法(静态方法)
function Counter.get_total()
    return Counter.count
end

local c1 = Counter:new()
local c2 = Counter:new()
print(c1:get_id())         -- 1
print(c2:get_id())         -- 2
print(Counter.get_total()) -- 2

三、继承 #

3.1 单继承 #

lua
-- 父类
local Animal = {}
Animal.__index = Animal

function Animal:new(name)
    local instance = setmetatable({}, self)
    instance.name = name
    return instance
end

function Animal:speak()
    print(self.name .. " makes a sound")
end

-- 子类
local Dog = setmetatable({}, {__index = Animal})
Dog.__index = Dog

function Dog:new(name, breed)
    local instance = Animal.new(self, name)
    instance.breed = breed
    return instance
end

function Dog:speak()
    print(self.name .. " says: Woof!")
end

-- 子类
local Cat = setmetatable({}, {__index = Animal})
Cat.__index = Cat

function Cat:new(name, color)
    local instance = Animal.new(self, name)
    instance.color = color
    return instance
end

function Cat:speak()
    print(self.name .. " says: Meow!")
end

-- 使用
local dog = Dog:new("Buddy", "Golden Retriever")
local cat = Cat:new("Whiskers", "Orange")

dog:speak()  -- Buddy says: Woof!
cat:speak()  -- Whiskers says: Meow!

3.2 调用父类方法 #

lua
local Animal = {}
Animal.__index = Animal

function Animal:new(name)
    return setmetatable({name = name}, self)
end

function Animal:introduce()
    print("I am an animal named " .. self.name)
end

local Dog = setmetatable({}, {__index = Animal})
Dog.__index = Dog

function Dog:new(name, breed)
    local instance = Animal.new(self, name)
    instance.breed = breed
    return instance
end

function Dog:introduce()
    -- 调用父类方法
    Animal.introduce(self)
    print("I am a " .. self.breed)
end

local dog = Dog:new("Buddy", "Golden Retriever")
dog:introduce()
-- I am an animal named Buddy
-- I am a Golden Retriever

3.3 多重继承 #

lua
local function create_class(...)
    local parents = {...}
    local class = {}
    
    -- 查找方法
    local function search(key, parents)
        for _, parent in ipairs(parents) do
            if parent[key] then
                return parent[key]
            end
        end
    end
    
    setmetatable(class, {
        __index = function(_, key)
            return search(key, parents)
        end
    })
    
    class.__index = class
    
    function class:new(...)
        local instance = setmetatable({}, self)
        if instance.init then
            instance:init(...)
        end
        return instance
    end
    
    return class
end

-- 使用
local A = {value_a = "A"}
function A:method_a()
    print("Method A: " .. self.value_a)
end

local B = {value_b = "B"}
function B:method_b()
    print("Method B: " .. self.value_b)
end

local C = create_class(A, B)

function C:init(x)
    self.value_a = x
    self.value_b = x
end

local c = C:new("X")
c:method_a()  -- Method A: X
c:method_b()  -- Method B: X

四、封装 #

4.1 私有成员 #

lua
local BankAccount = {}
BankAccount.__index = BankAccount

function BankAccount:new(initial_balance)
    -- 私有变量
    local balance = initial_balance or 0
    
    local instance = setmetatable({}, self)
    
    -- 公共方法访问私有变量
    function instance:deposit(amount)
        balance = balance + amount
    end
    
    function instance:withdraw(amount)
        if amount <= balance then
            balance = balance - amount
            return true
        end
        return false
    end
    
    function instance:get_balance()
        return balance
    end
    
    return instance
end

local account = BankAccount:new(100)
account:deposit(50)
print(account:get_balance())  -- 150
-- account.balance = 0  -- 无效,balance 是私有的

4.2 保护成员 #

lua
local Person = {}
Person.__index = Person

function Person:new(name, age)
    local instance = setmetatable({}, self)
    instance._name = name  -- 保护成员(约定)
    instance._age = age
    return instance
end

function Person:get_name()
    return self._name
end

function Person:get_age()
    return self._age
end

function Person:set_age(age)
    if age > 0 then
        self._age = age
    end
end

五、多态 #

5.1 方法重写 #

lua
local Shape = {}
Shape.__index = Shape

function Shape:new(name)
    return setmetatable({name = name}, self)
end

function Shape:area()
    return 0
end

function Shape:perimeter()
    return 0
end

function Shape:describe()
    print(string.format("%s: area=%.2f, perimeter=%.2f",
        self.name, self:area(), self:perimeter()))
end

local Rectangle = setmetatable({}, {__index = Shape})
Rectangle.__index = Rectangle

function Rectangle:new(width, height)
    local instance = Shape.new(self, "Rectangle")
    instance.width = width
    instance.height = height
    return instance
end

function Rectangle:area()
    return self.width * self.height
end

function Rectangle:perimeter()
    return 2 * (self.width + self.height)
end

local Circle = setmetatable({}, {__index = Shape})
Circle.__index = Circle

function Circle:new(radius)
    local instance = Shape.new(self, "Circle")
    instance.radius = radius
    return instance
end

function Circle:area()
    return math.pi * self.radius ^ 2
end

function Circle:perimeter()
    return 2 * math.pi * self.radius
end

-- 多态
local shapes = {
    Rectangle:new(3, 4),
    Circle:new(5),
    Rectangle:new(2, 6)
}

for _, shape in ipairs(shapes) do
    shape:describe()
end
-- Rectangle: area=12.00, perimeter=14.00
-- Circle: area=78.54, perimeter=31.42
-- Rectangle: area=12.00, perimeter=16.00

六、类工厂 #

6.1 通用类创建器 #

lua
local function class(parent)
    local c = {}
    c.__index = c
    
    if parent then
        setmetatable(c, {__index = parent})
    end
    
    function c:new(...)
        local instance = setmetatable({}, self)
        if instance.init then
            instance:init(...)
        end
        return instance
    end
    
    function c:extend()
        return class(self)
    end
    
    return c
end

-- 使用
local Animal = class()

function Animal:init(name)
    self.name = name
end

function Animal:speak()
    print(self.name .. " makes a sound")
end

local Dog = Animal:extend()

function Dog:init(name, breed)
    Animal.init(self, name)
    self.breed = breed
end

function Dog:speak()
    print(self.name .. " says: Woof!")
end

local dog = Dog:new("Buddy", "Golden Retriever")
dog:speak()  -- Buddy says: Woof!

七、接口与混入 #

7.1 混入模式 #

lua
-- 定义混入
local Printable = {
    print_info = function(self)
        print(tostring(self))
    end
}

local Comparable = {
    __eq = function(a, b)
        return a:value() == b:value()
    end,
    __lt = function(a, b)
        return a:value() < b:value()
    end
}

-- 应用混入
local function mixin(class, ...)
    for _, m in ipairs({...}) do
        for k, v in pairs(m) do
            class[k] = class[k] or v
        end
    end
end

local Item = {}
Item.__index = Item

function Item:new(value)
    return setmetatable({value = value}, self)
end

function Item:value()
    return self.value
end

function Item:__tostring()
    return "Item(" .. self.value .. ")"
end

mixin(Item, Printable, Comparable)

local a = Item:new(10)
local b = Item:new(20)

a:print_info()  -- Item(10)
print(a < b)    -- true

八、总结 #

本章介绍了 Lua 面向对象编程:

  1. 对象基础:表和冒号语法
  2. 类实现:构造函数、方法
  3. 继承:单继承、多重继承
  4. 封装:私有成员、保护成员
  5. 多态:方法重写
  6. 类工厂:通用类创建器
  7. 混入模式:代码复用

下一章,我们将学习协程。

最后更新:2026-03-27