Lua 本身不是一个面向对象的语言,但它提供了强大而灵活的机制来实现面向对象编程(OOP)的概念。本章将探讨如何在 Lua 中实现类、对象、继承和多态等 OOP 特性。

6.1 使用表实现类

在 Lua 中,我们使用表和函数来模拟类和对象。

基本类的实现

  1. local Dog = {}
  2. Dog.__index = Dog
  3. function Dog.new(name)
  4. local self = setmetatable({}, Dog)
  5. self.name = name
  6. return self
  7. end
  8. function Dog:bark()
  9. print(self.name .. " says: Woof!")
  10. end
  11. -- 使用类
  12. local myDog = Dog.new("Buddy")
  13. myDog:bark() -- 输出: Buddy says: Woof!

6.2 方法和self参数

在 Lua 中,self 是一个隐含的参数,代表调用方法的对象实例。

使用冒号语法

  1. function Dog:eat(food)
  2. print(self.name .. " is eating " .. food)
  3. end
  4. myDog:eat("kibble") -- 输出: Buddy is eating kibble

冒号语法 : 自动将调用对象作为第一个参数(self)传递给方法。

6.3 继承的实现

Lua 使用元表来实现继承。

  1. local Animal = {}
  2. Animal.__index = Animal
  3. function Animal.new(name)
  4. local self = setmetatable({}, Animal)
  5. self.name = name
  6. return self
  7. end
  8. function Animal:speak()
  9. print(self.name .. " makes a sound")
  10. end
  11. -- Cat 继承自 Animal
  12. local Cat = setmetatable({}, {__index = Animal})
  13. Cat.__index = Cat
  14. function Cat.new(name)
  15. local self = setmetatable(Animal.new(name), Cat)
  16. return self
  17. end
  18. function Cat:speak()
  19. print(self.name .. " meows")
  20. end
  21. -- 使用
  22. local myCat = Cat.new("Whiskers")
  23. myCat:speak() -- 输出: Whiskers meows

6.4 多态

多态允许不同类的对象对同一消息做出响应。

  1. local function makeSound(animal)
  2. animal:speak()
  3. end
  4. local myDog = Dog.new("Rex")
  5. local myCat = Cat.new("Fluffy")
  6. makeSound(myDog) -- 输出: Rex says: Woof!
  7. makeSound(myCat) -- 输出: Fluffy meows

6.5 私有成员的模拟

Lua 没有内置的私有成员机制,但我们可以使用闭包来模拟。

  1. function Dog.new(name)
  2. local age = 0 -- 私有变量
  3. local self = setmetatable({}, Dog)
  4. self.name = name
  5. function self:getAge()
  6. return age
  7. end
  8. function self:haveBirthday()
  9. age = age + 1
  10. end
  11. return self
  12. end
  13. local myDog = Dog.new("Spot")
  14. myDog:haveBirthday()
  15. print(myDog:getAge()) -- 输出: 1
  16. print(myDog.age) -- 输出: nil

6.6 元方法和运算符重载

元方法允许自定义表的行为,包括运算符重载。

  1. local Vector = {}
  2. Vector.__index = Vector
  3. function Vector.new(x, y)
  4. return setmetatable({x = x, y = y}, Vector)
  5. end
  6. function Vector:__add(other)
  7. return Vector.new(self.x + other.x, self.y + other.y)
  8. end
  9. function Vector:__tostring()
  10. return "(" .. self.x .. ", " .. self.y .. ")"
  11. end
  12. local v1 = Vector.new(1, 2)
  13. local v2 = Vector.new(3, 4)
  14. local v3 = v1 + v2
  15. print(v3) -- 输出: (4, 6)

6.7 面向对象设计模式

单例模式

  1. local Singleton = {}
  2. function Singleton.getInstance()
  3. if not Singleton.instance then
  4. Singleton.instance = {
  5. data = 0,
  6. incrementData = function(self)
  7. self.data = self.data + 1
  8. end
  9. }
  10. end
  11. return Singleton.instance
  12. end
  13. local s1 = Singleton.getInstance()
  14. local s2 = Singleton.getInstance()
  15. s1:incrementData()
  16. print(s2.data) -- 输出: 1

工厂模式

  1. local ShapeFactory = {}
  2. function ShapeFactory.createShape(shapeType)
  3. if shapeType == "circle" then
  4. return {
  5. draw = function() print("Drawing a circle") end
  6. }
  7. elseif shapeType == "square" then
  8. return {
  9. draw = function() print("Drawing a square") end
  10. }
  11. else
  12. error("Unsupported shape type")
  13. end
  14. end
  15. local circle = ShapeFactory.createShape("circle")
  16. circle.draw() -- 输出: Drawing a circle

6.8 实践项目:简单的图形库

让我们创建一个简单的图形库来演示面向对象编程的概念。

  1. -- Shape 基类
  2. local Shape = {}
  3. Shape.__index = Shape
  4. function Shape.new()
  5. return setmetatable({}, Shape)
  6. end
  7. function Shape:draw()
  8. error("Draw method must be implemented by subclasses")
  9. end
  10. -- Circle
  11. local Circle = setmetatable({}, {__index = Shape})
  12. Circle.__index = Circle
  13. function Circle.new(radius)
  14. local self = setmetatable(Shape.new(), Circle)
  15. self.radius = radius
  16. return self
  17. end
  18. function Circle:draw()
  19. print("Drawing a circle with radius " .. self.radius)
  20. end
  21. -- Rectangle
  22. local Rectangle = setmetatable({}, {__index = Shape})
  23. Rectangle.__index = Rectangle
  24. function Rectangle.new(width, height)
  25. local self = setmetatable(Shape.new(), Rectangle)
  26. self.width = width
  27. self.height = height
  28. return self
  29. end
  30. function Rectangle:draw()
  31. print("Drawing a rectangle " .. self.width .. "x" .. self.height)
  32. end
  33. -- 使用图形库
  34. local shapes = {
  35. Circle.new(5),
  36. Rectangle.new(4, 6),
  37. Circle.new(3)
  38. }
  39. for _, shape in ipairs(shapes) do
  40. shape:draw()
  41. end

练习

  1. 扩展图形库,添加更多形状(如三角形)和其他方法(如计算面积)。
  2. 实现一个简单的动物层次结构,包括不同种类的动物和它们的特定行为。
  3. 创建一个基本的银行账户系统,支持不同类型的账户(如储蓄账户、支票账户)和常见的银行操作。

通过本章的学习,你应该能够在 Lua 中实现面向对象编程的核心概念,并应用这些概念来设计和构建更复杂的系统。记住,虽然 Lua 不是一个传统的面向对象语言,但它提供了足够的灵活性来实现强大的面向对象设计。