Lua学习记录 — (10)面向对象-类(公有私有属性/静态,重写,运算符重载,继承等等)

BjaClass类模拟包——点击下载

ObjectOriented.lua

------------------------------------ Lua面向对象 ------------------------------------
-- Lua中没有直接的类定义方法;(需要通过模拟来实现)

-------------------- 类的封装 --------------------
-- Lua中的类可以通过 table 来模拟实现;

do
    --- 构建类表(每个对象都将类表设置为元表,类表中的对象都是静态的)
    BaseClass = {}
    BaseClass.__index = BaseClass -- 此步骤当BaseClass作为元表时,能够基表访问到(否则静态属性无法访问);
    BaseClass.__newindex = function(object,k,v) -- 此步骤使通过obj更改ClassA的静态变量时,能够作用在ClassA上(否则只能通过BaseClass.静态名 = xxx 更改静态变量);
        -- 这么处理是避免obj操作非静态变量时,直接作用在BaseClass表上;
        if BaseClass[k] then    -- 当Class上存在k键时,说明这个是静态变量;
            BaseClass[k] = v
        else    -- 否则,则操作对象obj自身的成员;
            rawset(object,k,v)
        end
    end
    -- 创建对象私有表
    BaseClass.createPrivateTable = function(object)
        local private = {}
        -- 元表索引向基类对象的private表,索引更新也指向基类对象的private表(避免更新数据时,重复创建private数据)
        setmetatable(private,{__index = object.private,__newindex = object.private})
        object.private = private
        return private
    end

    --- 构建类元表(如果不继承,可以不构建元表,构造器使用 BaseClass:new() 来定义)
    local Class_MT = {}
    setmetatable(BaseClass,Class_MT)  -- 此处元表作用:1.继承;2.创建Class()形式的构造器
    -- 无继承
    Class_MT.__index = {}
    --- 构造器(利用了元方法,以实现Class()格式即可创建对象)
    Class_MT.__call = function(tbl,arg)
        --- 创建BaseClass的对象(函数结束一定要返回它)
        local obj = {}
        local private = BaseClass.createPrivateTable(obj)
        setmetatable(obj,BaseClass)

        --- 私有成员(通过闭包的性质实现)
        -- 属性
        private._privateMember = "BaseClass privateMember"
        -- 方法(私有方法没什么意义,可以用公有替代)
        private._privateFunc = function() print("BaseClass 调用了私有函数,本对象的arg = " .. obj.arg) end

        --- 公有成员(每个obj都会生成各自对应的成员)
        -- 属性
        obj.publicMember = "BaseClass publicMember"
        obj.arg = arg or 0

        --- 返回对象
        return obj
    end

    --- 静态属性
    -- 公有(内外部都可以直接通过 "类名.静态名" 访问静态属性了)
    BaseClass.publicStaticMember = "BaseClass publicStaticMember"
    -- 私有(内部直接使用 "静态名" 访问私有静态)
    local privateStaticMember= "BaseClass privateStaticMember"

    --- 静态方法
    -- 公有(不能访问对象的成员)
    BaseClass.publicStaticFunc = function()
        print("这里是 BaseClass 公有静态函数")
    end
    -- 私有
    local privateStaticFunc = function()
        print("这里是 BaseClass 私有静态函数")
    end

    --- 公有 函数成员
    -- 操作公有成员属性(只用到公有成员的情况下,这种方法较好,每个obj共用一个函数,较少占内存)
    function BaseClass:ShowPublicMember()
        if BaseClass == self then
            error("不可通过Class名直接访问成员,请使用对象访问")
            return
        end
        print(self.publicMember)
    end
    -- 方法:获取私有属性()
    function BaseClass:getPrivateMember() return self.private._privateMember end
    -- 方法:设置私有属性()
    function BaseClass:setPrivateMember(str) self.private._privateMember = str end
    -- 方法:调用私有函数
    function BaseClass:publicFunc()
        print("BaseClass 调用了公有函数,本对象的arg = ".. self.arg .. "接下来调用私有函数:")
        self.private._privateFunc()
    end

    --- 运算符重载
    -- 重载加号
    BaseClass.__add = function(obj1,obj2)
        if obj1 == BaseClass or obj2 == BaseClass then
            error("不可直接对BaseClass类作加法运算,请使用对象操作")
            return
        end
        return obj1.arg + obj2.arg
    end

end

-------------------- 封装测试

do
    print("==================== 《封装测试》 ====================")
    -- 创建对象objA
    local objA = BaseClass(1)
    print("\n=====objA基本成员属性展示=====")     --> =====objA基本成员属性展示=====
    -- 展示对象的成员
    print(objA.publicMember)                        --> BaseClass publicMember
    -- 调用对象的函数
    objA:publicFunc()                               --> BaseClass 调用了公有函数,本对象的arg = 1接下来调用私有函数:
    -- 通过公有函数获取私有成员                           BaseClass 调用了私有函数,本对象的arg = 1
    str = "这个是改变前的私有成员属性:%s"
    print(str:format(objA:getPrivateMember()))      --> 这个是改变前的私有成员属性:BaseClass privateMember
    -- 通过公有函数改变私有成员,再展示
    objA:setPrivateMember("objA BaseClass privateMember")
    str = "这个是改变后的私有成员属性:%s"
    print(str:format(objA:getPrivateMember()))      --> 这个是改变后的私有成员属性:objA BaseClass privateMember

    -- 创建对象objB
    local objB = BaseClass(3)

    -- 上面改变了objA的私有成员,现在访问objB的私有成员(不冲突)
    print("\n=====objA的私有成员已改变,现在访问objB的私有成员=====")     --> =====objA的私有成员已改变,现在访问objB的私有成员=====
    str = "objA的私有变量:%s,objB的私有变量:%s"
    print(str:format(objA:getPrivateMember(),objB:getPrivateMember()))   --> objA的私有变量:objA BaseClass privateMember,objB的私有变量:BaseClass privateMember

    -- 改变objA的公有成员,再访问objB的公有成员(不冲突)
    print("=====接着改变objA的公有成员,再访问objB的公有成员=====")        --> =====接着改变objA的公有成员,再访问objB的公有成员=====
    objA.publicMember = "objA BaseClass publicMember"
    str = "objA的公有变量:%s,objB的公有变量:%s"
    print(str:format(objA.publicMember,objB.publicMember))          --> objA的公有变量:objA publicMember,objB的公有变量:BaseClass publicMember

    -- 访问BaseClass静态成员
    print("\n=====BaseClass静态成员测试=====")            --> =====BaseClass静态成员测试=====
    print("更改前 " .. BaseClass.publicStaticMember)        --> 更改前 BaseClass publicStaticMember
    BaseClass.publicStaticMember = "new publicStaticMember"
    print("更改后 " .. objA.publicStaticMember)             --> 更改后 new publicStaticMember
    objA.publicStaticMember = 123
    print("通过对象更改后 " .. objB.publicStaticMember)    --> 通过对象更改后 objA publicStaticMember
    BaseClass.publicStaticFunc()                            --> 这里是 BaseClass 公有静态函数
    objB.publicStaticFunc()                                 --> 这里是 BaseClass 公有静态函数

    -- 运算符重载
    print("\n=====BaseClass运算符重载测试=====")   --> =====BaseClass运算符重载测试=====
    print("objA + objB = " .. objA+objB)          --> objA + objB = 4
end


-------------------- 类的继承 --------------------
-- 可以通过metatable元表的__index来模拟实现;

do
    --- 构建类表
    DerivedClass = {}
    DerivedClass.__index = DerivedClass -- 此步骤当DerivedClass 作为元表时,能够基表访问到(否则静态属性无法访问);
    DerivedClass.__newindex = function(object,k,v) -- 此步骤使通过obj更改DerivedClass的静态变量时,能够作用在DerivedClass上(否则只能通过DerivedClass.静态名 = xxx 更改静态变量);
        -- 这么处理是避免obj操作非静态变量时,直接作用在BaseClass表上;
        if DerivedClass[k] then    -- 当Class上存在k键时,说明这个是静态变量;
            DerivedClass[k] = v
        else    -- 否则,则操作对象obj自身的成员;
            rawset(object,k,v)
        end
    end
    -- 创建对象私有表
    DerivedClass.createPrivateTable = function(object)
        local private = {}
        -- 元表索引向基类对象的private表,索引更新也指向基类对象的private表(避免更新数据时,重复创建private数据)
        setmetatable(private,{__index = object.private,__newindex = object.private})
        object.private = private
        return private
    end

    --- 构建类元表
    local Class_MT = {}
    setmetatable(DerivedClass,Class_MT)  -- 此处元表作用:1.继承;2.创建Class()形式的构造器
    -- 继承BaseClass
    Class_MT.__index = BaseClass
    --- 构造器(利用了元方法,以实现Class()格式即可创建对象)
    Class_MT.__call = function(Class,arg)
        --- 创建ClassA的对象(函数结束一定要返回它)
        local obj = BaseClass(arg)
        local private = DerivedClass.createPrivateTable(obj)
        setmetatable(obj,DerivedClass)

        --- 重写私有属性
        private._privateMember = "DerivedClass privateMember"

        --- 重写公有属性
        obj.publicMember = "DerivedClass publicMember"
        obj.arg = arg or 0

        --- 返回对象
        return obj
    end

    --- 新的静态变量
    DerivedClass.newPublicStaticMember = "DerivedClass newPublicStaticMember"

    --- 重写公有方法
    function DerivedClass:publicFunc()
        print("DerivedClass 调用了公有函数,本对象的arg = ".. self.arg .. "接下来调用私有函数:")
        self.private._privateFunc()
    end

    --- 运算符重载(重载运算符无法继承)
    -- 重载减号
    DerivedClass.__sub = function(obj1,obj2)
        if obj1 == BaseClass or obj2 == BaseClass then
            error("不可直接对BaseClass类作加法运算,请使用对象操作")
            return
        end
        return obj1.arg - obj2.arg
    end

end

-------------------- 继承测试
do
    print("\n\n==================== 《继承测试》 ====================")
    -- 创建对象objA
    local objA = DerivedClass(5)
    print("\n=====objA基本成员属性展示=====")     --> =====objA基本成员属性展示=====
    -- 展示对象的成员
    print(objA.publicMember)                        --> DerivedClass publicMember
    -- 调用对象的函数
    objA:publicFunc()                               --> DerivedClass 调用了公有函数,本对象的arg = 5接下来调用私有函数:
    -- 通过公有函数获取私有成员                           BaseClass 调用了私有函数,本对象的arg = 5
    str = "这个是改变前的私有成员属性:%s"
    print(str:format(objA:getPrivateMember()))      --> 这个是改变前的私有成员属性:DerivedClass privateMember
    -- 通过公有函数改变私有成员,再展示
    objA:setPrivateMember("objA DerivedClass privateMember")
    str = "这个是改变后的私有成员属性:%s"
    print(str:format(objA:getPrivateMember()))      --> 这个是改变后的私有成员属性:objA DerivedClass privateMember

    -- 创建对象objB
    local objB = DerivedClass(3)
    -- 上面改变了objA的私有成员,现在访问objB的私有成员(不冲突)
    print("\n=====objA的私有成员已改变,现在访问objB的私有成员=====")     --> =====objA的私有成员已改变,现在访问objB的私有成员=====
    str = "objA的私有变量:%s,objB的私有变量:%s"
    print(str:format(objA:getPrivateMember(),objB:getPrivateMember()))   --> objA的私有变量:objA DerivedClass privateMember,objB的私有变量:DerivedClass privateMember

    -- 改变objA的公有成员,再访问objB的公有成员(不冲突)
    print("=====接着改变objA的公有成员,再访问objB的公有成员=====")        --> =====接着改变objA的公有成员,再访问objB的公有成员=====
    objA.publicMember = "objA DerivedClass publicMember"
    str = "objA的公有变量:%s,objB的公有变量:%s"
    print(str:format(objA.publicMember,objB.publicMember))          --> objA的公有变量:objA DerivedClass publicMember,objB的公有变量:DerivedClass publicMember

    -- 访问BaseClass静态成员
    print("\n=====DerivedClass静态成员测试=====")            --> =====DerivedClass静态成员测试=====
    print("更改前 " .. DerivedClass.publicStaticMember)        --> 更改前 123
    DerivedClass.publicStaticMember = "new publicStaticMember"
    print("更改后 " .. objA.publicStaticMember)             --> 更改后 new publicStaticMember
    objA.publicStaticMember = 999
    print("通过对象更改后 " .. objB.publicStaticMember)    --> 通过对象更改后 999
    print("BaseClass的静态成员 " .. BaseClass.publicStaticMember)    --> BaseClass的静态成员 123
    DerivedClass.publicStaticFunc()                            --> 这里是 BaseClass 公有静态函数
    objB.publicStaticFunc()                                 --> 这里是 BaseClass 公有静态函数
    print(DerivedClass.newPublicStaticMember)           --> DerivedClass newPublicStaticMember

    -- 运算符重载(重载运算符无法继承)
    print("\n=====BaseClass运算符重载测试=====")   --> =====BaseClass运算符重载测试=====
    print("objA - objB = " .. objA-objB)          --> objA + objB = 2
end

----- 类的多态
-- Lua中模拟的类天然支持多态
do
    print("\n\n==================== 《多态测试》 ====================")
    local base = BaseClass(5)
    local Derived = DerivedClass(10)

    base:publicFunc()       --> BaseClass 调用了公有函数,本对象的arg = 5接下来调用私有函数:
    --                          BaseClass 调用了私有函数,本对象的arg = 5
    base = Derived
    base:publicFunc()       --> DerivedClass 调用了公有函数,本对象的arg = 10接下来调用私有函数:
    --                      --  BaseClass 调用了私有函数,本对象的arg = 10
end

BjaClass类模拟包——点击下载

BjaClassExample.lua

-------------------- 完整的类(示例)--------------------
BjaClass = require("BjaClass")
do
    --- 创建一个类(作为基类)
    People = BjaClass.MakeClass()

    --- 创建构造器
    local cotr = function(class,name,age,id)
        --- 创建对象(函数结束一定要返回它)
        local obj = BjaClass.MakeObj(class)

        People.counter = People.counter + 1

        --- 公有成员
        obj.name = name or "none"
        obj.age = age or 0

        --- 私有成员
        obj.private._tag = "peop"
        obj.private._id = id or People.counter

        --- 返回对象
        return obj
    end
    BjaClass.MakeCtor(People,cotr)

    --- 静态变量
    People.counter = 0  -- 公有
    People.privateStatic._type = "people"  -- 私有

    --- 静态方法
    People.ShowCount = function(self)print("People 的数量是 " .. self.counter) end    -- 公有
    People.GetType = function(self)return self.privateStatic._type end    -- 公有

    --- 公有成员方法
    function People:introduce()
        if self == People then
            error("不能通过类直接调用非静态成员!")
            return nil
        end
        local format = "我叫%s,今年%d岁!"
        print(format:format(self.name,self.age))
    end
    function People:getId()
        if self == People then
            error("不能通过类直接调用非静态成员!")
            return nil
        end
        return self.private._id
    end
    function People:getTag()
        if self == People then
            error("不能通过类直接调用非静态成员!")
            return nil
        end
        return self.private._tag
    end

    --- 运算符重载
    People.__add = function(obj1,obj2)
        if obj1.age and obj2.age then
            return obj1.age + obj2.age
        end
        return nil
    end
    People.__lt = function(obj1,obj2)
        local num1,num2 = 0,0
        if type(obj1)=="number"  then
            num1 = obj1
        else
            num1= obj1.age
        end
        if type(obj2)=="number"  then
            num2 = obj2
        else
            num2= obj2.age
        end


        return (num1 < num2)
    end

end

do
    --- 创建一个类(派生至People)
    Programmer = BjaClass.MakeClass(People)

    --- 创建构造器
    local cotr = function(class,name,age,id)
        --- 创建对象(函数结束一定要返回它)
        local obj = BjaClass.MakeObj(class,name,age,id)

        --- 公有成员
        obj.career = "Unity3D程序员"

        --- 重写私有成员
        obj.private._tag = "prog"

        --- 返回对象
        return obj
    end
    BjaClass.MakeCtor(Programmer,cotr)

    --- 重写静态变量
    Programmer.privateStatic._type = "programmer"  -- 私有

    --- 重写公有成员方法
    function Programmer:introduce()
        if self == Programmer then
            error("不能通过类直接调用非静态成员!")
            return nil
        end
        local format = "我叫%s,今年%d岁,是一名%s!"
        print(format:format(self.name,self.age,self.career))
    end

end

do
    print("\n\n==================== 《示例测试》 ====================")

    print("(1)")
    boy = People("BeiJiaan",25)
    boy:introduce()                                     --> 我叫BeiJiaan,今年25岁!
    People:ShowCount()                                  --> People 的数量是 1
    print("People的Type = " .. boy:GetType())     --> People的Type = people
    print("boy的Id = " .. boy:getId())               --> boy的Id = 1
    print("boy的Tag = " .. boy:getTag())             --> boy的Tag = peop

    print("(2)")
    beijiaan = Programmer("贝哥哥",25)
    beijiaan:introduce()                                    --> 我叫贝哥哥,今年25岁,是一名Unity3D程序员!
    Programmer:ShowCount()                                  --> People 的数量是 2
    print("Programmer的Type = " .. beijiaan:GetType()) --> Programmer的Type = programmer
    print("beijiaan的Id = " .. beijiaan:getId())         --> beijiaan的Id = 2
    print("beijiaan的Tag = " .. beijiaan:getTag())       --> beijiaan的Tag = prog

    print("(3)")
    print("boy's age + beijiaan's age = " .. boy + beijiaan)  --> boy's age + beijiaan's age = 50.0
    print("beijiaan's age + boy's age = " .. beijiaan + boy)  --> beijiaan's age + boy's age = 50.0

    print("boy's age > 30? " .. tostring(boy > 30))       --> boy's age < 30? false
    print("beijiaan's age > 30? " .. tostring(beijiaan > 30))   --> 报错!!!attempt to compare number with table
end

你可能感兴趣的:(Script(python,Lua,Javascript))