当前位置: 首页 > news >正文

【Lua学习笔记】Lua进阶——Table(4)继承,封装,多态

在这里插入图片描述

文章目录

  • 封装
  • 继承
  • 多态


封装

// 定义基类
Object = {}//由于表的特性,该句就相当于定义基类变量
Object.id =1//该句相当于定义方法,Object可以视为定义的对象,Test可以视为方法名
//我们知道Object是一个表,但是抽象地看,请把Object看着面向对象中的 “对象”
function Object:Test()print(self.id)
end
// 以上语句等同于:
// public class Object{int id=1;void Test(Object obj)print(obj.id);
}//定义一个new方法,用于创建这个基类的对象
function Object:new()//定义空表obj,用面向对象比喻相当于new了一个空对象local obj = {}//绑定元表,将元表看作一个基类self.__index = selfsetmetatable(obj, self)//返回空对象return obj
endlocal Car = Object:new()  //实际是将new出的空对象return给外部定义的Car
// 以上语句等同于:
// Object Car = new Object();// 由于Car实际上是空的table,所以访问Car其实是通过__index访问基类中的索引
// 相当于虽然没有定义Car内的变量,但初始化时继承基类的值作为了初始值
print(Car.id) --1,来自元表// 同样的,Car实际使用了__index基类提供的方法
// 但是由于入参是self,此处就是Car,print(Car.id),最终还是访问了基类__index找到的Object.id
Car:Test() --1,来自元表// 定义Car中的变量
Car.id = 2
// 现在Car表中有了索引id,那么就能找到这个索引,所以输出为2
Car:Test() --2,来自子表

现在我们可以像面向对象一样,new一个对应基类的对象了。但是这里的new也不完全相似与面向对象的new,例如我们可以这样做:

Car.name = "a"
print(Car.name)
输出:
a

我们在封装Object类的时候可完全没有name这个索引,而在Lua中我们new了一个新对象,还能新加入一些变量和方法,这些特性明显是继承了父类的子类才有的。算不上坏处,不过我们想要完全实现封装还能加以限制:

//定义一个垃圾列表,将添加到子类的垃圾都丢进去
garbage={}//定义一个new方法,用于创建这个基类的对象
function Object:new()//定义空表obj,用面向对象比喻相当于new了一个空对象local obj = {}// 禁止子类的添加self.__newindex = garbage//绑定元表,将元表看作一个基类self.__index = selfsetmetatable(obj, self)//返回空对象return obj
end
local Car = Object:new()
Car.name = "a"
print(Car.name)输出:
nil

现在我们确实实现封装了,既能访问基类的方法和变量,又能阻止新加的其他东西,但是还得把垃圾及时清理,这点我们将在后文垃圾回收中讲解。


继承

面向对象重要的特性之继承,光new一个新对象无法满足全部需要,我们想要重写父类的一些方法而非直接使用它们,就需要继承。

观察上面的Object:new()代码,其实我们如果想用进行继承,其实只需要在上面改改即可

Object = {}
Object.id = 1;
function Object:Test()print(self.id)
end//换种方式,如果我们不return的话,想要返回这个值,可以直接把它丢进全局表中
function Object:subClass(className)_G[className] = {}self.__index = selfsetmetatable(_G[className], self)
end
Object:subClass("Cat")
print(Cat.id)
输出:
1

继承比封装还要简单一点,其实它和我们第一次定义的封装是一模一样的,只是换了种方式来实现。

// new一个Cat类的对象
local WhiteCat = Cat:new()
print(WhiteCat.id) -- 1
function Object:Test()print("我是基类")
endfunction Object:new()local obj = {}self.__newindex = garbageself.__index = selfsetmetatable(obj, self)return obj
endfunction Object:subClass(className)_G[className] = {}self.__index = selfsetmetatable(_G[className], self)
end//Cat继承基类
Object:subClass("Cat")
//new一个Cat类的对象WhiteCat
local WhiteCat = Cat:new()
WhiteCat:Test()  -- 我是基类// 重写Test方法(其实只是新写了一个放在Cat表里被调用,更像重载?)
function Cat:Test()print("我是猫类")
end
WhiteCat:Test()  --我是猫类//想要重写Cat的Test方法?不好意思我已经用__newindex封装好了
//白猫是个对象,而不是Cat这个类,它不应该重写方法
//下面重写的方法会被丢到garbage里
function WhiteCat:Test()print("我是白猫")
end
WhiteCat:Test() --我是猫类
garbage:Test() --我是白猫

如果看不明白,建议重学Table,元表以及面向对象


多态

多态就是对于一个父类的相同方法,子类可以执行不同的逻辑。实现多态我们可以怎么做?

  1. 重写和重载方法
  2. 实现接口
  3. 实现抽象类和抽象方法

如果重写应当是这样:

function Object:Test()print("我是基类")
end
Object:subClass("Cat")
Object:subClass("Dog")
function Cat:Test()print("我是猫类")
end
function Dog:Test()print("我是狗?")
end

重写固然可以实现,问题在于继承了父类之后的重写是无法保留父类的同名方法的,那我想要访问父类的方法怎么办?

别忘了我们的类其实是个table,我直接把父类存进去,然后要使用的时候访问不就行了吗?反正又没有面向对象语法限制。

function Object:subClass(className)_G[className] = {}local obj = _G[className]self.__index = self// 直接把父类表存进子类的baseobj.base = selfsetmetatable(obj , self)
endfunction Dog:Test()print("我是狗?")
end
Dog:Test()
Dog.base:Test()输出:
我是狗?
我是基类function Dog:Test()// 如果想在继承了父类的方法的基础之上重写self.base:Test()print("我是狗?")
endDog:Test() --我是基类 我是狗?

注意,如果我们直接用的父类方法,在调用父类的时候应当避免不同的类共享全局变量:

Object = {}
Object.id = 1;
function Object:Test()self.id = self.id + 1print(self.id)
endObject:subClass("Cat")
function Cat:Test()self.base:Test()print("我是猫类")
end
Object:subClass("Dog")
function Dog:Test()self.base:Test()print("我是狗?")
end输出:
2
我是猫类
3
我是狗?

原因也很简单,table内存放了父类的table,我们直接调用父类的Test方法,那么self.id每次调用都会加一。两个table中的父类是同一个地址,而Object:Test()这个方法中每次传入给self的都是这个xxx.base,也就是这个父类table本身,所以self.id增加的是父类中的id,作为一个全局变量,它自然是不断增加的。

那么我们想让子类既能在继承Object:Test()这个父类方法基础之上重写,又想使得self.id改变的self是我们使用方法的那个子类table,那么就应当这样写:

Object = {}
Object.id = 1;
function Object:Test()self.id = self.id + 1print(self.id)
endObject:subClass("Cat")
function Cat:Test()// 手动地传入参数,因为冒号传入给self的是base// 因此需要手动地改变传入的参数的值self.base.Test(self)print("我是猫类")
end
Cat:Test()输出:
2
我是猫类

重载应该是最简单的多态方法,只需要改变函数的入参数量就行了

至于接口和抽象类,lua本身的函数就可以重写,抽象性还是很强的。而接口我们应当可以访问另一个table结构来实现,例如self.base应当就能视为一种接口,当然这些只是我的想法,目前还没学习到。

相关文章:

【Lua学习笔记】Lua进阶——Table(4)继承,封装,多态

文章目录 封装继承多态 封装 // 定义基类 Object {}//由于表的特性,该句就相当于定义基类变量 Object.id 1//该句相当于定义方法,Object可以视为定义的对象,Test可以视为方法名 //我们知道Object是一个表,但是抽象地看&#xff…...

安全性证明(四)Practical Identity-Based Encryption Without Random Oracles

...

Linux中常用的指令

ls ls [选项] [目录或文件] 功能:对于目录,列出该目录下所有的子目录和文件;对于文件,列出该文件的文件名和其他属性 常用选项: -a:列出目录下的所有文件,包括以.开头的隐藏文件 -l:列出文件的详细信息。…...

【java】【面对对象高级4】内部类、枚举、泛型

目录 1、内部类 1.1 成员内部类【了解】 1.1.1 定义 1.1.2 扩展变量 1.2 静态内部类【了解】 1.2.1 定义 1.2.2 扩展变量 1.3 局部内部类【了解】 1.4 匿名内部类【重点】 1.4.1 定义 1.4.1.1 常规写法 1.4.1.2 匿名内部类改造 1.4.2 匿名内部类的常见使用场景 1.4.2…...

Python的用处到底是什么?(三)

11. 数据库操作:Python的库,如sqlite3和SQLAlchemy,可以连接和操作各种类型的数据库。 Python提供了一些库和工具,如sqlite3和SQLAlchemy,用于连接和操作各种类型的数据库。以下是关于这两个库的详细解释:…...

【Nodejs】Express基本使用

Express 中文网 基于 Node.js 平台,快速、开放、极简的 web 开发框架。 1.Express的安装方式 Express的安装可直接使用npm包管理器上的项目,在安装npm之前可先安装淘宝镜像: npm install -g cnpm --registryhttps://registry.npmmirror.com/…...

k8s集群安装v1.20.9

参考网上资料并将异常问题解决,经测试可正常安装集群。 1.我的环境准备 本人使用vmware pro 17新建三个centos7虚拟机,每个2cpu,20GB磁盘存储,内存2GB,其中主节点的内存3GB,可使用外网. 2.所有节点安装D…...

Staples Drop Ship EDI 需求分析

Staples 是一家美国零售公司,总部位于马萨诸塞州弗拉明汉,主要提供支持工作和学习的产品和服务。该公司于 1986 年在马萨诸塞州布莱顿开设了第一家门店。到 1996 年,该公司已跻身《财富》世界 500 强,后来又收购了办公用品公司 Qu…...

模型调参及优化

调参 调权重参数,偏置参数 训练数据集用来训练参数w,b 调超参数 验证数据集用来选择超参数学习率lr,隐藏层大小等 如何调参 当泛化误差和训练误差都没有降下去说明欠拟合;当训练误差降下去,但泛化误差出现上升形式&…...

多数据源数据转换和同步的ETL工具推荐

有许多支持多数据源数据转换和同步的ETL工具可供选择。以下是一些常见的ETL工具和它们支持多数据源数据转换和同步的特点: Apache NiFi:Apache NiFi是一个开源的ETL工具,支持多种数据源的连接,包括文件系统、数据库、消息队列、网…...

配置 gitlab https 访问

文章目录 1. 备份2. 生成SSL证书3. 配置文件4. 重启5. 访问 1. 备份 docker exec -ti gitlab-ce gitlab-rake gitlab:backup:create2. 生成SSL证书 yum install openssl openssl-devel -y mkdir /data/gitlab/config/ssl ; cd /data/gitlab/config/ssl### 生成证书 openssl…...

Kepware Modbus驱动简介

1. Modbus驱动能够解决什么问题? 它是Modbus设备驱动的集合,为用户提供一种方便快捷的Modbus设备数采解决方案。 只需要通过简单的配置就可以将常见的例如Modbus TCP/IP Ethernet、RTU Serial 和 ASCII Serial等协议设备无缝连接到 HMI/SCADA、MES/His…...

从零开始学习CTF——CTF是什么

引言: 从2019年10月开始接触CTF,学习了sql注入、文件包含等web知识点,但都是只知道知识点却实用不上,后来在刷CTF题才发现知识点的使用方法,知道在哪里使用,哪里容易出漏洞,可是在挖src漏洞中还…...

为Android构建现代应用——主体结构

创建Screents和ViewModels 在前面的章节中,我们已经分析了OrderNow项目的理论概念和我们将赋予的组织。 在本章中,我们将开始实现初始结构和模板,这将联接每一个应用程序的部分。 首先将添加以下带有各自视图模型的主屏幕: •…...

【shell脚本】shell脚本之日志切割(进阶实战三)

恭喜你,找到宝藏博主了,这里会分享shell的学习整过程。 shell 对于运维来说是必备技能之一,它可以提高很多运维重复工作,提高效率。 shell的专栏,我会详细地讲解shell的基础和使用,以及一些比较常用的she…...

VMLogin和虚拟机里的浏览器有什么区别?

虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。 指纹浏览器,也称防关联浏览器。 简单来说,就是允许在同一台电设备上操作和管理多个平台、多个账号,账…...

unimrcp server的session资源分配与回收

unimrcp使用APR的内存池管理内存,因此,处理函数中一般都会传递一个pool指针,需要内存时,就从pool里分配一块,一般也不需要关心内存的释放。因为,一路呼叫关联一个session,一个session对应一个po…...

【图论】三种中心性 —— 特征向量、katz 和 PageRank

维基百科:在图论和网络分析中,中心性指标为图中相应网络位置的节点分配排名或数值。中心性这一概念最初起源于社交网络分析,因此很多衡量中心性的术语也反映了其社会学背景。 不同中心性指标对 “重要” 的衡量方式不同,因此适用于…...

[sqoop]将hive查询后的数据导入到MySQL

一、知识点 export:将Hive的表导入到mysql叫导出 搜了很多,发现sqoop在hive导出到mysql时 1)不支持where参数对数据进行过滤。 2)不支持指定hive表的方式导出,只能指定Hive目录进行导出。 二、操作 1、在MySQL中建表 creat…...

Linux df、du命令

df:查看文件系统硬盘使用情况 df 命令,用于显示 Linux 系统中各文件系统的硬盘使用情况,包括文件系统所在硬盘分区的总容量、已使用的容量、剩余容量等。 df 命令的基本格式为: [rootlocalhost ~]# df [选项] [目录或文件名] df…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

基于服务器使用 apt 安装、配置 Nginx

🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...

SpringCloudGateway 自定义局部过滤器

场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、👨‍🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨‍&#x1f…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

JavaScript 数据类型详解

JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...