• Lua学习笔记(五):面向对象的实现


    Lua本身是没有class之类的关键字的,但是我们可以巧妙利用function也是值和table的特性来实现面向对象的特性。

    通过复制表的实现

    Lua中的类也是一个table对象,下面我们看看一个简单的类的定义:

     1 People = {}--定义表 People
     2 
     3 --添加方法的第一种方式
     4 People.talk = function()
     5   print("people talk.")
     6 end
     7 
     8 --添加方法的第二种方式
     9 function People.say()
    10   print("people say.")
    11 end
    12 
    13 People.talk()--people talk.
    14 People.say()--people say.

    我们发现添加一个方法有两种方式,这两种方式的效果都是一致的,至于使用哪种就看个人喜好了。

    通过拷贝创建实例

    不知道大家发现没有,上面的示例中并没有创建实例这个步骤,而在面向对象中,类是需要创建实例来使用的,下面我们就用复制的方法来创建实例:

     1 --克隆一个表
     2 function clone(obj)
     3   local instance = {}
     4   
     5   for key, var in pairs(obj) do
     6       instance[key] = var
     7   end
     8   
     9   return instance;
    10 end
    11 
    12 People = {}--定义表 People
    13 
    14 --定义方法
    15 People.talk = function()
    16   print("people talk.")
    17 end
    18 
    19 --创建 People 的实例
    20 local p = clone(People)
    21 p.talk()--people talk.

    构造函数

    我们发现虽然可以创建实例了,但是却没有构造函数,下面我们把构造函数也添加进去:

     1 --克隆一个表
     2 function clone(obj)
     3   local instance = {}
     4   
     5   for key, var in pairs(obj) do
     6       instance[key] = var
     7   end
     8   
     9   return instance;
    10 end
    11 
    12 People = {}--定义表 People
    13 
    14 --定义构造函数
    15 People.new = function(name)
    16   local ins = clone(People)
    17   ins.name = name;
    18   return ins
    19 end 20 21 --定义方法 22 People.talk = function(self) 23 print(self.name.." talk.") 24 end 25 26 --创建 People 的实例 27 local p = People.new("Li Lei") 28 p.talk(p)--people talk. 29 p:talk()--使用 : 号可以省略 self 的填写, 效果和上一行一致

    这里引入了一个新的变量self和“:”符号,下面我们来说说:

    self

    self作为第一个参数表示调用则本身。

    .号和:号

    调用时为了传递调用者本身,所以第一个参数需要将自身传入,这是.号的写法;

    如果使用:号,则默认第一个参数传入调用者本身,无需我们再写第一个参数了,我们可以从第二个参数开始写,但是函数声明时仍然要写第一个参数self的。

    定义函数时也可以使用:号进行定义,这样定义方法时也可以省略self参数,但是写法只能写成function tab:foo() end这样的形式,如下:

     1 obj = {name = "Li Lei"}
     2 --.号的写法和调用
     3 obj.foo1 = function()
     4   print "foo1"
     5 end
     6 function obj.foo2(self)
     7   print(self.name.."foo2")
     8 end
     9 obj.foo1()--foo1
    10 obj.foo2(obj)--Li Leifoo2
    11 --:号的写法和定义
    12 --[[注释掉的这种写法是不允许的
    13 obj:foo3 = function()
    14   print(self.name.."foo3")
    15 end
    16 ]]
    17 function obj:foo4()
    18   print(self.name.."foo4")
    19 end
    20 obj:foo4()--Li Leifoo4

    继承

    下面我们来看看如何实现类的继承:

     1 --克隆一个表
     2 function clone(obj)
     3   local instance = {}
     4   
     5   for key, var in pairs(obj) do
     6       instance[key] = var
     7   end
     8   
     9   return instance;
    10 end
    11 
    12 People = {}--定义表 People
    13 
    14 --定义构造函数
    15 People.new = function(name)
    16   local ins = clone(People)
    17   ins.name = name;
    18   return ins
    19 end
    20 
    21 --定义方法
    22 People.talk = function(self)
    23   print(self.name.." talk.")
    24 end
    25 
    26 --定义方法2
    27 People.talk2 = function(self)
    28   print(self.name.." talk2.")
    29 end
    30 
    31 --创建 People 的实例
    32 local p = People.new("Li Lei")
    33 p.talk(p)--people talk.
    34 p:talk()--使用 : 号可以省略 self 的填写, 效果和上一行一致
    35 
    36 --下面是关于继承的实现
    37 
    38 --将 origin 表的值复制到 dist 表中
    39 function copy(origin, dist)
    40   for key, var in pairs(origin) do
    41       dist[key] = var
    42   end
    43 end
    44 
    45 Man = {}--定义表 Man, 继承自 People
    46 
    47 Man.new = function(name)
    48   local ins = People.new(name)--创建继承的类, 这样就拥有了继承类的所有属性
    49   copy(Man, ins)--将 Man 的属性附加到实例
    50   return ins
    51 end
    52 
    53 --定义方法
    54 Man.say = function()
    55   print("Man say!")
    56 end
    57 
    58 --重写方法
    59 Man.talk2 = function(self)
    60   print(self.name.." talk2. (Man)")
    61 end
    62 
    63 --创建 Man 的实例
    64 local m = Man.new("Han Meimei")
    65 m:talk()--Han Meimei talk.
    66 m:talk2()--Han Meimei talk2. (Man)
    67 m:say()--Man say!

    简单来说,就是先创建父类的实例,然后把新类的所有属性都拷贝到刚创建的实例上即可。

    通过函数闭包的实现

    我们可以通过在函数内定义函数的方式来实现面向对象的特性:

     1 --定义方法直接返回表的实例
     2 function People(name)
     3   local ins = {}--创建表
     4   
     5   --初始化函数
     6   local function init()
     7     ins.name = name
     8   end
     9   
    10   --定义方法
    11   ins.talk = function()
    12     print(ins.name.." talk.")
    13   end
    14   
    15   --定义带参数的方法
    16   ins.talk2 = function(content)
    17     print(ins.name.." talk "..content..".")
    18   end
    19   
    20   -- self 可以省去了, 因为可以通过闭包的特性获取到, 或者如果要统一 : 符号可以这么写
    21   ins.talk3 = function(self, content)
    22     print(self.name.." talk "..content..".")
    23   end
    24   
    25   init()--调用初始化函数
    26   
    27   return ins
    28 end
    29 
    30 --创建对象
    31 p = People("Li Lei")
    32 p:talk()--没有参数可以这么写
    33 p.talk()
    34 
    35 --p:talk2("hello")--没有 self 参数不能这么调用了
    36 p.talk2("hello")
    37 
    38 p:talk3("hello 2")
    39 p.talk3(p, "hello 2")

    这种写法的运行效率略低于上一种方法,但是却更加清晰,在实际使用时推荐使用该方法来编写类。

    继承

    使用这种写法也可以实现类的继承,如下:

     1 --定义方法直接返回表的实例
     2 function People(name)
     3   local ins = {}--创建表
     4   
     5   --初始化函数
     6   local function init()
     7     ins.name = name
     8   end
     9   
    10   --定义方法
    11   ins.talk = function()
    12     print(ins.name.." talk.")
    13   end
    14   
    15   --定义带参数的方法
    16   ins.talk2 = function(content)
    17     print(ins.name.." talk "..content..".")
    18   end
    19   
    20   -- self 可以省去了, 因为可以通过闭包的特性获取到, 或者如果要统一 : 符号可以这么写
    21   ins.talk3 = function(self, content)
    22     print(self.name.." talk "..content..".")
    23   end
    24   
    25   init()--调用初始化函数
    26   
    27   return ins
    28 end
    29 
    30 --下面是继承的代码
    31 
    32 function Man(name)
    33   local ins = People(name)--关键: 创建一个 People 类的实例
    34   
    35   --添加新项目
    36   ins.say = function()
    37     print(ins.name.." say.")
    38   end
    39   
    40   --覆写老方法
    41   ins.talk = function()
    42     print(ins.name.." talk. (Man)")
    43   end
    44   
    45   return ins
    46 end
    47 
    48 m = Man("Han Meimei")
    49 m.say()--Han Meimei say.
    50 m.talk()--Han Meimei talk. (Man)

    其实就是创建父类的对象后添加新的属性,比较容易理解。

  • 相关阅读:
    Git 使用记录
    vue threejs
    git如何忽略历史中的文件
    SwiftUI init函数中查询并赋值数据
    SwiftUI Binding数据类型转换
    隐私政策
    Apple开发_神奇资源汇总
    centos安装python记录
    LINUX服务器运行Python出现ModuleNotFoundError的解决方案
    创建Django项目过程
  • 原文地址:https://www.cnblogs.com/hammerc/p/4709133.html
Copyright © 2020-2023  润新知