zoukankan      html  css  js  c++  java
  • 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
    
    --输出相等
    
  • 相关阅读:
    第 28 章 CSS3 多列布局
    实例解读什么是Redis缓存穿透、缓存雪崩和缓存击穿
    深入浅出一致性Hash原理
    要想深入理解mysql索引?这16个点你必须要了解!
    为什么不要尝试用int来存手机号?
    mysql-覆盖索引
    聚集索引,非聚集索引,覆盖索引 原理
    mysql use index、ignore index、force index用法
    HashMap在JDK1.8版本尾插法实现解析
    redis slot 槽点
  • 原文地址:https://www.cnblogs.com/Fflyqaq/p/13292388.html
Copyright © 2011-2022 走看看