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

--輸出相等


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM