您的位置:首页 > 编程语言 > Lua

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

2018-02-04 01:41 561 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐