Lua面向对象 -- 多重继承、私密性


1. 多重继承之在多个类中查找一个字段

其实多重继承没什么特别的,除非两个将要被继承的类有相同的函数名和属性,否则,处理起来很简单。

 

无非就是在多个table中查找某个字段而已,不简单吗?Lua里的继承就是在别人的table里查找自己不存在的字段罢了。

那么,单继承与多重继承的差别也在这里,一个是只查找一个table,另一个是查找两个或以上的table。

我们就先来看看如何从2个或多个table中查找某个字段,如下代码:

1
2
3
4
5
6
7
8
9
10
11
function search(classes, key)
     for  i = 1, #classes  do
         local value = classes[i][key];
         if  value ~= nil then
             return  value;
         end
     end
end
local t1 = {name =  "hehe" };
local t2 = {game =  "who" };
print(search({t1, t2},  "game" ));

这里的classes参数,是一个table,这个table里又存放了多个table,也就是我们想要继承的那些类。而key就是要查找的字段。

只需要遍历所有的table,判断这个字段是否在某个table里,找到之后,就返回这个值。

我们的测试代码就是从t1、t2中查找game这个字段,t1、t1可以看成是两个类。

输出结果如下:

[LUA-print] who

 

2.多重继承之创建继承多个类的子类

刚刚的search函数很简单吧?别急着开心,那只是预热一下而已,真正创建多重继承的函数比较复杂。

如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function createClass(...)
     local parents = {...};
     local child = {};
    
     -- 设置类的元表
     setmetatable(child, {
         __index = function(table, key)
             return  search(parents, key);
         end
     })
    
     -- 给类新增一个 new 函数,用于创建对象
     function child: new ()
         o = {};
         setmetatable(o, child);
         child.__index = child;
         return  o;
     end
    
     -- 返回这个继承了多个类的子类
     return  child;
end

createClass函数就是用来创建一个继承了多个类的子类,有点小复杂,慢慢分析:

1) 参数是一个可变参数,我们要将多个被继承的类作为参数传递进来

2) parents用于保存这些被继承的类

3) 创建一个新的table——child,它就是我们想要的那个继承了多个类的子类

4) 给child设置元表,并且设置__index元方法,__index元方法可以是一个函数,当它是一个函数时,它的参数就是元表所属的table,以及要查找的字段名。

5) 我们在__index元方法函数里调用search函数,从多个父类中查找所需的字段。于是,当调用child的某个函数时,就会从各个父类中查找,这已经完成了继承的工作了。

6) 接下来就是我们所熟悉的new函数,用来创建child的子类,实现方式和上一篇所说的是一样 ,如果你忘记了,可以看看这篇文章

7) 最后返回child,一切都完成了。

 

看似很复杂,其实还是对__index的应用而已。

我们赶紧来测试一下吧,如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-- 一个精灵类
TSprite = {}
function TSprite:hello()
       print( "谁跟你hello!" );
end
    
function TSprite: new ()
       o = {}
       setmetatable(o, self);
       self.__index = self;
       return  o;
end
    
-- 一个子弹类
TBullet = {}
function TBullet:fire()
       print( "别动,再动我就瞄不准了!" );
end
function TBullet: new ()
       o = {}
       setmetatable(o, self);
       self.__index = self;
       return  o;
end
    
-- 继承了两个类的子类
local BulletSprite = createClass(TSprite, TBullet);
    
-- 子类的对象
local bSprite = BulletSprite: new ();
bSprite:hello();
bSprite:fire();

这里创建了两个类:TSprite和TBullet。

然后调用createClass函数,创建一个继承了TSprite和TBullet的子类。

最后创建子类的对象,调用对象的hello和fire函数。

输出结果如下:

[LUA-print] 谁跟你hello!

[LUA-print] 别动,再动我就瞄不准了!

怎么样?很简单吧~

 

3.类的私密性

这里来说一个和多重继承无关的技巧,那就是私密性。

对于Java、C++等语言,我们都很熟悉,public、private、protected等关键词。

这些关键词让封装成为了可能。

 

然后,Lua里是没有私密这种说法的,类也是一个table,table的所有字段都是可以调用的,并没有说哪些是公有的,哪些是私有的。

如果有某些函数和属性不希望被外部调用,那么,也可以,不过这种实现方式看起来很别扭:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function createTSprite()
     local self = {name =  "benmutou" };
     local function myBus()
         print( "myBus是我自己的函数,你不能直接调用" );
     end
     local function myGame()
         print( "myGame是我自己的函数,你不能直接调用" );
     end
     local function hello()
         print( "hello:" );
         myBus();
     end
     local function hi()
         print( "hi:" );
         myGame();
     end
    
     local function setName(newName)
         self.name = newName;
     end
    
     return  {hello = hello, hi = hi, setName = setName};
end

我们已经不需要用到冒号来定义函数了,这个类的name、myBus、myGame都是不希望给外部直接调用的。

调用createTSprite函数后,会返回一个新的table,这个table仅仅存放了一些字段,这些字段就是能够被外部直接调用的函数或者是属性。

来看看测试代码:

1
2
3
local sp = createTSprite();
sp.hello();
sp.hi();


输出结果如下:

[LUA-print] hello:

[LUA-print] myBus是我自己的函数,你不能直接调用

[LUA-print] hi:

[LUA-print] myGame是我自己的函数,你不能直接调用

这样,我们创建的对象就只能使用hello、hi、setName函数。

而其他的name、myBus、myGame只能通过这几个能使用的函数去调用,而不能直接调用。

这样就能完成私密性了。

 

不过,我个人有点迷糊,因为这已经不太像一个类的样子了。

 

4.结束

好了,关于面向对象的内容,暂时介绍到这里。可能介绍的都比较基础,目的是为了巩固Lua基础。


来源网址:http://www.benmutou.com/archives/1800

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值