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

golang学习笔记21-面向对象(三):封装与继承【重要】

本节也是GO核心部分,很重要。
注:本人已有C,C++,Python基础,只写本人认为的重点。由于导包语句已经在19讲(笔记19:面向对象的引入)展示过了,所以这里就不展示了。

一、封装

【1】什么是封装:
封装(encapsulation)就是把抽象出的字段和对字段的操作封装在一起,数据被保护在内部程序的其它包只有通过被授权的操作方法,才能对字段进行操作。
【2】封装的好处:
1)隐藏实现细节
2)提可以对数据进行验证,保证安全合理
【3】Golang中如何实现封装:
1)建议将结构体、字段(属性)的首字母小写(其它包不能使用,类似private,实际开发不小写也可能,因为封装没有那么严格)
2)给结构体所在包提供一个工厂模式的函数,首字母大写(类似一个构造函数)
3)提供一个首字母大写的Set方法(类似其它语言的public),用于对属性判断并赋值func (var结构体类型名)SetXxx(参数列表){//加入数据验证的业务逻辑var.Age =参数
}
4)提供一个首字母大写的Get方法(类似其它语言的public),用于获取属性的值func (var结构体类型名)GetXxx()(返回值列表){
return var.字段;
}
示例:
在utils中定义结构体和方法:

type person struct {
	Name string
	age  int //其他包不能直接访问
}

//相当于构造器
func NewPerson(name string) *person {
	return &person{
		Name: name,
	}
}

func (p *person) SetAge(age int) {
	if age < 0 || age > 150 {
		fmt.Println("请输入合理的年龄!")
		return
	}
	p.age = age
}
func (p *person) GetAge() int {
	return p.age
}

然后在main中调用:

func main() {
	// 使用构造器创建一个新的 person 实例
	p := utils.NewPerson("李华")

	// 设置年龄
	p.SetAge(30)

	// 获取年龄并打印
	fmt.Printf("姓名: %s, 年龄: %d\n", p.Name, p.GetAge())

	// 尝试设置不合理的年龄
	p.SetAge(200) // 输出: 请输入合理的年龄!

	// 再次获取年龄并打印
	fmt.Printf("姓名: %s, 年龄: %d\n", p.Name, p.GetAge())
}

二、继承

继承的概念和C++一样,就不做赘述了,但GO其实是弱化了这个概念,没有专门的机制来实现继承,具体来说,没有父类子类的概念,没有继承关键字,但可以通过匿名结构体实现。首先,在utils中定义结构体和方法:

type Animal struct {
	Age    int
	Weight float64
}

func (a *Animal) ShowInfo() {
	fmt.Println("年龄=", a.Age, "体重=", a.Weight)
}
func (a *Animal) Shout() {
	fmt.Println("我是动物,我会喊叫")
}

//用Animal是为了提高复用性,显然Cat是Animal的子类
type Cat struct {
	Animal
}

func (c *Cat) Scratch() {
	fmt.Println("我是小猫,我可以挠人")
}

这里cat中的animal显然就是匿名结构体,即没有名字,只有类型的结构体,属于cat的父类。
定义好子类和父类后,在main中调用:

func main() {
	c := &utils.Cat{}
	//方式1
	c.Animal = utils.Animal{Age: 3, Weight: 10.6}
	// 方式2:c.Animal.Age, c.Animal.Weight = 3, 10.6
	c.Animal.ShowInfo()
	c.Animal.Shout()
	c.Scratch()
}

一些细节:
【1】结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段、方法,都可以使用。读者可自行尝试,这里不做赘述。
【2】匿名结构体字段访问可以简化。例:

func main() {
	c := &utils.Cat{}
	c.Age, c.Weight = 3, 10.6
	c.ShowInfo()
	c.Shout()
	c.Scratch()
}

上述程序输出和通过animal访问是一样的,这证明了子类完全继承了父类的方法和字段,这样使用起来就方便很多。
【3】当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近原则访问,如希望访问匿名结构体的字段和方法,可以通过匿名结构体名来区分。这句话说白了就是子类和父类变量冲突,比如cat也有一个Age,优先用子类的,如果仍然想用父类的,那么字段访问就不能简化,要显示调用父类。读者可自行尝试,这里不做赘述。
【4】 Golang中支持多继承:如一个结构体嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承。为了保证代码的简洁性,建议大家尽量不使用多重继承,很多语言就将多重继承去除了,但是Go中保留了。多重继承的示例如下:

type A struct {
	Aa int
	Ab string
}
type B struct {
	Bc int
	Bd string
	Aa int
}
type C struct {
	A
	B
}

C的创建语句是c:=C{A{},B{}}
显然,C有两个父类,更多测试代码就不写了。
【5】如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体类型名来区分。比如上一点的A和B中有相同字段,那么和第三点一样,显示调用父类即可。
【6】结构体的匿名字段可以是基本数据类型。也就是说,可以在子类里面写int,float等基本数据类型,调用时就类似c.int,c.float64,…,这个了解即可。
【7】嵌入匿名结构体的指针也是可以的。如果嵌入指针,比如cat里面嵌入*animal,那么创建cat时,要在animal前加取地址符&(与号),使用时用*解引用即可。
【8】结构体的字段可以是结构体类型的(组合模式)。这个其实就是二重结构体,除了访问时还可以再“点”一下,和其他类型没什么区别,当然,这不是继承。示例:
utils内的定义:

type D struct {
	Da int
	Db string
	Dc B //组合模式
}

main中的调用:

func main() {
	d := utils.D{10, "ooo", utils.B{66, "ppp", 99}}
	fmt.Println(d)
	fmt.Println(d.Dc.Bd)
}

程序输出为:

{10 ooo {66 ppp 99}}
ppp

http://www.kler.cn/a/329016.html

相关文章:

  • 25. 架构能力
  • 【支持向量机(SVM)】:算法原理及核函数
  • M|告白(2024)
  • JWT 过期后 自动刷新方案
  • 设计模式-Adapter(适配器模式)GO语言版本
  • 探索 HTML 和 CSS 实现的 3D旋转相册
  • Spring Boot助力IT领域交流平台开发
  • ffmpeg拉取rtsp网络视频流报错解析
  • XPath基础知识点讲解——用于在XML中查找信息的语言
  • Redis 篇-深入了解 Redis 中的 RESP 通信协议与内存回收(过期 key 处理、内存淘汰策略)
  • CentOS系统yum出现Could not retrieve mirrorlist问题
  • G502 鼠标自定义(配合 karabiner)
  • 【算法竞赛】堆
  • 前端框架中@路径别名原理和配置
  • 在线代码编辑器
  • 【数据库】在 Java 中使用 MongoDB 进行数据聚合
  • 【系统代码】招投标采购一体化管理系统,JAVA+vue
  • 设置Android studio或者IEDA自动导包
  • 滚雪球学Oracle[8.3讲]:区块链与Oracle
  • RM服务器研究(一)
  • [大语言模型-论文精读] 悉尼大学-ACL2024-提升大型语言模型的复杂视觉推理能力
  • jupyter使用pytorch
  • 详解调用钉钉AI助理消息API发送钉钉消息卡片给指定单聊用户
  • Vscode、小皮面板安装
  • 录屏软件大比拼:四款必备工具助你轻松录制精彩瞬间!
  • Java项目实战II基于Java+Spring Boot+MySQL的购物推荐网站的设计与实现(源码+数据库+文档)