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

厦门外贸建站小程序源码网

厦门外贸建站,小程序源码网,wordpress仿淘宝,淮安做网站.卓越凯欣文章目录 封装继承多态 封装 // 定义基类 Object {}//由于表的特性,该句就相当于定义基类变量 Object.id 1//该句相当于定义方法,Object可以视为定义的对象,Test可以视为方法名 //我们知道Object是一个表,但是抽象地看&#xff…

在这里插入图片描述

文章目录

  • 封装
  • 继承
  • 多态


封装

// 定义基类
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应当就能视为一种接口,当然这些只是我的想法,目前还没学习到。

http://www.dinnco.com/news/55733.html

相关文章:

  • 陇南网站设计收录好的网站
  • 友点企业网站管理系统模板白帽seo
  • 漫画网站建设教程视频网络热词2022
  • 网站制作公司 深圳长春网络科技公司排名
  • 莞城网站制作企业线上培训平台有哪些
  • 做网站运营跟专业有关吗上海还能推seo吗
  • 免费的网站搭建百度浏览器下载安装
  • 深圳企业建站模板建站模板免费下载
  • 做网站需要什么样的服务器西安百度推广开户运营
  • 关于网站建设的图片企业网站制作与维护
  • 网站整体风格爱站网长尾关键词挖掘
  • 网站做更改后台怎么做推广一手渠道
  • 东莞哪家网站建设广告投放渠道有哪些
  • 齐齐哈尔网架公司账号seo是什么
  • 个人版的wordpress怎么加关键词北京百度seo关键词优化
  • 网站正能量不用下载直接进入主页可以吗南平网站seo
  • asp+sql server典型网站建设案例(源码)3北京seo不到首页不扣费
  • 网站免费优化软件天津百度推广公司
  • 安徽设计公司厦门seo专业培训学校
  • 石家庄哪里有网站推广在线观看的seo综合查询
  • 上海设计网站百度做广告费用
  • 住房和城建设网站百度seo如何快速排名
  • 有了网站源码可以做网站吗淘宝关键词排名优化技巧
  • 太仓有没有做网站建设的腾讯与中国联通
  • 佛山做网站建设公司建站平台哪个好
  • 长沙做公司网站百度热榜
  • 怎么做自己地网站在线种子资源网
  • 网线水晶头接法seo怎么做优化工作
  • dell网站设计特色seo教程有什么
  • 网站搭建代理网站广告接入