LUA中的OOP(3) --- 多继承

最近比较忙,不太能保证每天抽出一个半小时下班前看书。今天要好点,下午测试了半天总算结束了,结果不错,心情很好。

总结下前几天看的lua中OOP多继承方面的东西,对应《lua中文手册》中多继承的部分。

之前谈到了单继承的实现是依靠为子类原型对象设置metatable,并令其__index成员指向父类的技术,来达到对应的目的。其实多继承也一样,究其本质来说,单继承的时候只需要搜索一个父类,现在需要搜索多个父类而已。为了达到这个目的,还是需要使用__index,只是这次我们不让__index指向一个父类原型对象,而是令其指向一个搜索函数,在这个搜索函数中,我们会遍历访问子类原型对象多继承的所有父类原型对象。

       要解决的问题有两个:1.)需要一个搜索函数来完成遍历工作 2.)需要将所有的多继承父类记录下来,否则等下你上哪搜索去?

      第一个问题简单,只要写对应的代码即可。第二个问题要麻烦一些。书上对第二个问题的解决方案使用了可变参函数+闭包,这确实是个非常不错的想法,可以令搜索函数的代码变得通用,同时可以将多继承函数作为一个OOP的原语,需要多继承时调用该原语并传递对应的子类和所有父类原型对象即可。来看实现细节:

<-----------------------------------------------------Code Begin-------------------------------------------------->

--下面是一组OOP的操作元语,用来表达 单继承 多继承 对象创建 原型对象声明 这样的语义
--同时也是在LUA中 OOP 的一套语法定义

-- 传递原型对象,和待创建对象,返回新创建的对应类型的对象
function CreateObject(proto_type, newobj)
newobj = newobj or {};
setmetatable(newobj, proto_type);
return newobj;
end


--让child原型对象继承base原型对象
function Inherit(child, base)
setmetatable(child, base)
end



--声明一个原型对象,使得可以使用CreateObject()创建该原型对象
--的实例对象,同时使得该原型对象可以被继承
function Class(proto_type)
proto_type.__index = proto_type

--为proto_type的metatable添加写保护,只允许读取metatable
proto_type.__metatable = proto_type
end


--多重继承元语,第一个参数为子类,后面的变参依次排列所有的父类
function InheritM(Child, ...)

Child = Child or {};

--设置子类的metatable.__index指向包含了所有父类作为闭包的函数
setmetatable(Child,
  { __index =function (tableobj, key)

                   {
                             --循环查找所有父类
                             for i =1, table.getn(arg), 1 do
                                     local value = arg[i][key];
                                     if value then
                                             return value;
                                     end
                             end

                             --在父类中也差找不到该成员,只能返回nil
                             return nil;
                             end
                   }
)


end



--首先定义human类的原型
do

local function __print_age(self)
print(string.format("human age = %d", self.age))
end


local function __set_age(self, value)
self.age = value;
end


local function __get_age(self)
return self.agel;
end

--定义human对象中公开方法的名称和对应的私有实现方法的映射关系
human = {
                    age = 0,
                    set_age = __set_age,
                    print_age = __print_age,
                   get_age = __get_age,
               };
--声明原型对象
Class(human)

end



--然后定义继承者Woman类的原型
do


local function __print_age(self)
print(string.format("woman age = %d", self.age))
end


woman ={
                           print_age = __print_age,
              };
--声明原型对象
Class(woman);
--这一步完成 单继承
Inherit(woman, human);

end

--对象实例测试代码


newobj0 = CreateObject(woman, {age = 25});
newobj1 = CreateObject(woman, {age = 24});

newobj1:print_age();
newobj0:print_age();

newobj0:set_age(15);

newobj1:print_age();
newobj0:print_age();

do

--定义并声明Boy类
boy =
{
       ageboy = 2;
}
Class(boy);

--boy原型对象将会同时继承woman原型对象和human原型对象
InheritM(boy, woman, human)

--继承后的对象实例测试代码
Obj0 = CreateObject(boy, {age = 99});
Obj1 = CreateObject(boy, {age = 100});

Obj0:print_age();
Obj1:print_age();

end

<-----------------------------------------------------Code End-------------------------------------------------->

多继承原语函数InheritM使用闭包和变参列表。使用闭包是为了产生一个给指定子类原型对象的metatable.__index专用的闭包函数(这里是指代函数携带了自身的运行环境数据,也就是闭包),该闭包中就保存了这个子类原型对象的所有父类原型对象集合,这就解决了前面提到的问题二。而使用变参列表,则使得InheritM具备了作为一个原语的能力:可以多继承的父类原型对象数目不受限制,在语法书写上也能有统一风格,这些都符合作为原语的必须条件。另外变参在lua中本身就是以一个固定名称的table来表示,在构造闭包时不需要新建任何table,直接在闭包函数中引用即可,省事省力省开销。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值