Lua 面向对象(实现类的创建和实例化、封装、继承、多态)




1、Lua面向对象基础

面向对象三大特性包括:封装、继承、多态。
还有在Lua中如何创建类和实例化,这里一一介绍

1.1、Lua类的创建和实例化

Test1.lua

--name,age就相当于字段。eat就相当于方法
person = {name = 'Ffly',age = 20}
function person:eat()
	print(self.name .. '该吃饭饭了,饿死了')
end

--这个方法用于实例化使用
function person:new()
	local self = {}
	--使用元表,并把__index赋值为person类
	setmetatable(self,{__index = person})
	
	return self
end

Test2.lua

--加载模块Test1.lua(类似于C#中的using引用)
--LuaStudio默认从软件根目录下加载
require "Test1"

--实例化person类
person1 = person:new()

person1:eat() --正常输出

1.2、Lua封装

--对age字段进行封装,使其只能用get方法访问
function newPerson(initAge)
	local self = {age = initAge};
	
	--三个方法
	local addAge = function(num)
		self.age = self.age + num;
	end
	local reduceAge = function(num)
		self.age = self.age - num;
	end
	local getAge = function(num)
		return self.age;
	end
	
	--返回时只返回方法
	return {
		addAge = addAge,
		reduceAge = reduceAge,
		getAge = getAge,
	}
end

person1 = newPerson(20)

--没有使用额外的参数self,用的是那里面的self表
--所以要用.进行访问
person1.addAge(10)
print(person1.age)        --输出nil
print(person1.getAge())   --输出30

1.3、Lua继承


--基类person,boy类继承于person
person = {name = "default",age = 0}
function person:eat()
	print(self.name .. '该吃饭饭了,饿死了')
end

--使用元表的 __index完成继承(当访问不存在的元素时,会调用)
function person:new(o)
	--如果o为false或者o为nil,则让o为{}
	o = o or {}
	setmetatable(o,self)
	--设置上面self的__index为表person
	self.__index = self
	
	return o
end

--相当于继承
boy = person:new()

--name在boy里找不到会去person里面找
print(boy.name)   --输出default
--修改了person里的值,并不会影响boy里面的值
boy.name = 'feifei'

print(person.name)   --输出default
print(boy.name)      --输出feifei

1.4、Lua多态

person = {name = "default",age = 0}

--重载
--简单方法:lua中会自动去适应传入参数的个数,所以我们可以写在一个方法里面

function person:eat(food)
	if food == nil then
		print(self.name .. '该吃饭饭了,饿死了')
	else
		print(self.name .. '喜欢吃:' .. food)
	end
end

function person:addAge(num)
	if num == nil then
		self.age = self.age + 1
	else
		self.age = self.age + num
	end
end

print(person:eat())
print(person:eat("大西瓜"))

person:addAge()
print(person.age)
person:addAge(5)
print(person.age)

--重写

function person:new(o)
	--如果o为false或者o为nil,则让o为{}
	o = o or {}
	setmetatable(o,self)
	--设置上面self的__index为表person
	self.__index = self
	
	return o
end

boy = person:new()
boy.name = "Ffly"
boy:eat()   --调用基类eat方法

--相当于重写eat方法
function boy:eat()
	print('小男孩' .. self.name .. '快要饿死了')
end
boy:eat()  --调用派生类eat方法

2、Lua面向对象进阶

2.1、class.lua的实现

class代码参考于云风大大的博客。

class.lua

--表_class的key为类,value为类的虚表
local _class={}

--为什么要使用虚表呢?
--[[
使用虚表的话,那么类本身的元素会是稳定的,
所有的变化都在虚表中进行,
这样 封装了变化、也便于继承的实现
]]


function class(super)
	
	--要创建的类class_type
	local class_type={}
	
	--构造函数,基类
	class_type.ctor=false
	class_type.super=super
	
	--class_type类型的虚表,虚表中包含class_type中的元素
	local vtb1={}
	_class[class_type]=vtb1
 
	--给类设置元表
	--在给表添加新元素时,会在虚表中也添加
	setmetatable(class_type,{
		__newindex = function(t,k,v) vtb1[k] = v end,
		__index = function(t,k) return vtb1[k] end,
	})
	

	--super不为空,表示为继承
	if super then
		setmetatable(vtb1,{__index=
			function(t,k)
				--从基类找要找的元素,找到就放入派生类虚表中
				local ret=_class[super][k]
				vtb1[k]=ret
				
				return ret
			end
		})
	end
	
	--给类型class_type创建实例对象
	--1、先依次从最顶层基类中调用构造方法
	--2、然后设置元表
	class_type.new=function(...) 
		
		--生成这个类对象
		local obj={}
		
		do
			local create
			
			--递归调用构造函数
			create = function(c,...)
				--super不为空,表示有基类
				if c.super then
					create(c.super,...)
				end

				--调用构造函数
				if c.ctor then
					c.ctor(obj,...)
				end
			end
			
 			create(class_type,...)
		end
		
		--设置obj的 __index为class_type的虚表
		setmetatable(obj,{ __index=_class[class_type] })
		
		return obj
	end
 
	return class_type
end

person.lua

require "class"

--创建基类person
person = class()
person.name = "Ffly"
person.age = 20

--设置person类的构造函数
function person:ctor()
	print("person:ctor 调用");
end

function person:eat()
	print(self.name .. "很饿,想吃东西")
end


--创建派生类boy,基类为person
boy = class(person)

function boy:ctor()
	print("boy:ctor 调用");
end

function boy:eat()
	print("boy " .. self.name .. "很饿,想吃东西")
end


--创建完两个类后,就可以使用了。
--创建boy类的实例boy1
boy1 = boy.new()
boy1:eat()


--[[
输出:
person:ctor 调用
boy:ctor 调用
boy Ffly很饿,想吃东西
]]

2.2、单例模式的实现

Boy.lua

require "class"

boy = class()

--单例模式的实现
boy.Instance = function()
	if (nil == boy.m_instance) then
		boy.m_instance = boy.new();
	end
	return boy.m_instance
end

function boy:ctor()
end

Singleton.lua

require "boy"

local b1 = boy.Instance()
local b2 = boy.Instance()

if b1==b2 then
	print("相等")
else
	print("不相等")
end

--输出相等
posted @ 2020-07-13 11:41  Fflyqaq  阅读(6368)  评论(3编辑  收藏  举报