Lua实现继承

Lua实现继承

我们知道在Lua脚本语言中是没有对象这个概念的。但是Lua为我们提供了一堆的元方法,可以实现类的继承

需求背景

  • 实现类似c++中的类
  • 实现类对类的继承
  • 实现类的多继承

什么是继承

继承是面向对象最显著的一个特性,继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。

实现类似C++中的类

  • 我们先不考虑继承的问题,首先来实现一个类的定义。

    • 实现

      local class = function (className)
      
          if type(className) ~= "string" then
              error("class name must string type")
          end
          local cls = {__className = className}
          cls.ctor = function ( ... ) 
              -- default constructor
          end
          cls.new = function ( ... )
              local instance = {}
              setmetatable(instance, {__index = cls})
              instance.__class = cls
              instance.ctor(...)
              return instance
          end
          cls.create = function ( ... )
              return cls.new(...) 
          end
          return cls
      end
      
    • 测试

          local ClassA = class("classA")
      
          function ClassA:ctor( ... )
          
              print("ClassA:ctor params is ", ...)
              self.name = ...
          end
          
          function ClassA:sayHello()
          
              print(string.format("my name is %s", self.name))
          end
          
          local classA_1 = ClassA:create("ClassA_1")
          classA_1:sayHello()
          print("=============================")
          local classA_2 = ClassA:create("ClassA_2")
          classA_2:sayHello()
          print("=============================")
          classA_1.name = "XXX"
          classA_1:sayHello()
          classA_2:sayHello()
      
    • 测试结果

          ClassA:ctor params is   ClassA_1
          my name is ClassA_1
          =============================
          ClassA:ctor params is   ClassA_2
          my name is ClassA_2
          =============================
          my name is XXX
          my name is ClassA_2
          [Finished in 0.0s]
      
  • 错误演示

    • 可能会有同学好奇,在测试代码中为什有如下代码

          classA_1.name = "XXX"
          classA_1:sayHello()
          classA_2:sayHello()
      

    这里是为了检测是否做到了由一个类,创建出来的两个对象是否做到了数据的隔离

    • class函数中的new函数做出如下修改,就会发现对象与对象之间数据混乱

          cls.new = function ( ... )
              cls.ctor(...)
              return cls
          end
      
    • 使用上面测试代码测试结果为

          ClassA:ctor params is   ClassA_1
          my name is ClassA_1
          =============================
          ClassA:ctor params is   ClassA_2
          my name is ClassA_2
          =============================
          my name is XXX
          my name is XXX
          [Finished in 0.0s]
      

    注意:一定要做好数据隔离,不然创建出来的对象数据就会混乱。这里只为类创建添加了构造函数,没有添加析构函数,可以仿造上面添加一个dtor析构函数

实现类对类的继承

在上面的取得的小成果上,继续扩展和完成class函数,从而实现类对类的继承。其实在我们只需要借鉴类的定义,将super作为cls__index元表即可。

  • cls添加一个super属性,并将super设置为cls__index元表,对上面class函数做出如下扩展

        local cls = {__className = className, __isClass = true}
        if type(super) == "table" then
            if not cls.__super then
                cls.__super = super
            end
        end
    
        cls.__index = cls
        if cls.__super then
            setmetatable(cls, {__index = cls.__super})
        end
    
  • 测试代码

        local BaseClass = class("BaseClass")
    
        function BaseClass:ctor( ... )
        
            print("BaseClass ctor")
        end
        
        function BaseClass:sayName(name)
        
            print(string.format("My name is %s", name))
        end
        
        
        local ChildClass = class("ChildClass", BaseClass)
        
        function ChildClass:ctor( ... )
        
            self.__super:create()
            print("ChildClass ctor")
            self:init()
        end
        
        function ChildClass:init( ... )
        
            self.name = "Hello"
        end
        
        function ChildClass:askName( ... )
        
            self:sayName(self.name)
            print("What's your name")
        end
        
        local childClass_1 = ChildClass:create()
        childClass_1:askName()
        print("childClass_1's name is ", childClass_1.name)
        print("=========================================")
        
        local childClass_2 = ChildClass:create()
        childClass_2:askName()
        childClass_1.name = "World"
        print("childClass_2's name is ", childClass_2.name)
        print("childClass_1's name is ", childClass_1.name)
        print("=========================================")
        
        local GrandsonClass = class("GrandsonClass", ChildClass)
        
        function GrandsonClass:ctor( ... )
        
            self.__super:create()
            print("GrandsonClass ctor")
        end
        
        local grandsonClass = GrandsonClass:create()
        grandsonClass.name = "grandsonClass"
        grandsonClass:askName()
    
  • 测试结果

    BaseClass ctor
    ChildClass ctor
    My name is Hello
    What's your name
    childClass_1's name is  Hello
    =========================================
    BaseClass ctor
    ChildClass ctor
    My name is Hello
    What's your name
    childClass_2's name is  Hello
    childClass_1's name is  World
    =========================================
    BaseClass ctor
    ChildClass ctor
    GrandsonClass ctor
    My name is grandsonClass
    What's your name
    [Finished in 0.0s]
    

注意:此处实现的是显示调用父类的构造函数,因此在子类的ctor函数中需要先初始化父类self.__super:create()

实现类的多继承

有了上面的基础,实现多继承也是轻而易举的事情了。我们只需要将__index设置成一个函数,然后遍历父类去用key去检索。当然这样多继承,也会存在一个问题,就是不同父类中有同名方法,或者同名属性,这个时候就和继承顺序与关系。在这里我们按照class("ClassName", SuperA, SuperB, ...)中书写先后顺序作为继承顺序,第一个设置为类的__super

  • 多继承实现

    class = function (className, ...)
    
        if type(className) ~= "string" then
            error("class name must string type")
        end
        local cls = {__className = className, __isClass = true}
        local supers = {...}
        for _, super in ipairs(supers) do
            local superType = type(super)
            assert(superType == nil or superType == "table" or superType == "function", string.format("create class %s with invalid super class type %s", className, type(super)))
            if superType == "function" then
                assert(cls.__create ~= nil, string.format("create class %s with more than one create", className))
                cls.__create = super
            elseif type(super) == "table" then
                cls.__supers = cls.__supers or {}
                cls.__supers[#cls.__supers + 1] = super
                if not cls.__super then
                    cls.__super = super
                end
            else
                error(string.format("create class %s with invalid super class type %s", className, type(super)))
            end
        end
        
    
        cls.__index = cls
        if not cls.__supers or #cls.__supers == 1 then
            setmetatable(cls, {__index = cls.__super})      
        else
            setmetatable(cls, {__index = function (_, key)
                local supers = cls.__supers
                for _, super in ipairs(supers) do
                    if super[key] then
                        return super[key]
                    end
                end
            end})
        end
        if not cls.ctor then -- default constructor
            cls.ctor = function ( ... )
    
            end
        end
        cls.new = function ( ... )
            local instance = {}
            setmetatable(instance, {__index = cls})
            instance.__class = cls
            instance.ctor(...)
            return instance
        end
        cls.create = function ( ... )
            return cls.new(...) 
        end
        return cls
    end
    
  • 测试

        local BaseClass = class("BaseClass")
        
        function BaseClass:ctor( ... )
        
            print("BaseClass ctor")
        end
        
        function BaseClass:sayName(name)
        
            print(string.format("My name is %s", name))
        end
        
        
        local SuperClass = class("SuperClass")
        
        function SuperClass:ctor( ... )
        
            print("SuperClass ctor")
        end
        
        function SuperClass:askName( ... )
        
            print(string.format("What's your name"))
        end
        
        
        local MakeFrinedClass = class("MakeFrinedClass", BaseClass, SuperClass)
        
        function MakeFrinedClass:ctor( ... )
        
            self.__super:create()
            print("MakeFrinedClass ctor")
        end
        
        function MakeFrinedClass:makeFriend( ... )
            
            self:sayName("MakeFrinedClass")
            self:askName()
        end
        
        local makeFrinedClass = MakeFrinedClass:create()
        makeFrinedClass:makeFriend()
    
  • 测试结果

        BaseClass ctor
        MakeFrinedClass ctor
        My name is MakeFrinedClass
        What's your name
        [Finished in 0.0s]
    

注意:这里的__super和创建类的时候父类的书写书序有关系,父类如果有同名函数或属性,具体条用那个属性或者函数也和父类书写书序有关系

欢迎讨论和纠正

[Email][email protected]

你可能感兴趣的:(Lua实现继承)