zoukankan      html  css  js  c++  java
  • 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(1)-git关联GitHub-windows-转载
    jenkins(4)-jenkins配置邮件通知
    jenkins(3)-linux下安装jenkins(yum install方式)
    【PAT甲级】1090 Highest Price in Supply Chain (25 分)(DFS)
    【PAT甲级】1087 All Roads Lead to Rome (30 分)(MAP【int,string】,邻接表,DFS,模拟,SPFA)
    【PAT甲级】1018 Public Bike Management (30 分)(DFS,SPFA)
    Educational Codeforces Round 61 (Rated for Div. 2) G(线段树,单调栈)
    Atcoder Grand Contest 032C(欧拉回路,DFS判环)
    Educational Codeforces Round 62 (Rated for Div. 2)E(染色DP,构造,思维,组合数学)
    Atcoder Grand Contest 031C(构造,思维,异或,DFS)
  • 原文地址:https://www.cnblogs.com/hammerc/p/4709133.html
Copyright © 2011-2022 走看看