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

16、做中学 | 初三上期 Golang面向对象_进阶

上篇定义一个结构体时候,实际上就是把一类事物的共有的属性(字段)和行为(方法)提取出来,形成一个物理模型(结构体)。这种研究问题的方法称为抽象。

接下来进行探索golang中的三大特性:封装、继承、多态!

一、封装

1. 什么是封装?

封装(encapsulation)就是把抽象出的字段和对字段的操作封装在一起,数据被保护在内部,程序的其它包只有通过被授权的操作(方法),才能对字段进行操作。

在这里插入图片描述
平常所看的电视,各种电路,电线进行封装隐藏,避免直接操作线路造成破坏和人身安全!

在代码中,我们把想封装的内容,进行封装隐藏,只暴露简单安全的访问通道!

2. 封装的好处

  1. 隐藏实现细节
  2. 提可以对数据进行验证,保证安全合理

3. 如何体现封装

  1. 对结构体中的属性进行封装
  2. 通过方法,包 实现封装

4. 封装的实现步骤

  1. 将结构体、字段(属性)的首字母小写(不能导出了,其它包不能使用,类似 private
  2. 给结构体所在包提供一个工厂模式的函数,首字母大写。类似一个构造函数
  3. 提供一个首字母大写的 Set 方法(类似其它语言的 public),用于对属性判断并赋值
  4. 提供一个首字母大写的 Get 方法(类似其它语言的 public),用于获取属性的值

在 Golang 开发中并没有特别强调封装,这点并不像 Java, Golang 本身对面向对象的特性做了简化的.

创建grade090包进行编写如下代码

package grade090type People struct {//  姓名 首字母大写 表示该字段是公共字段Name string// 年龄 首字母小写 表示该字段是私有字段age int
}// NewPeople 构造函数通过工厂方法进行创建
func NewPeople(name string) *People {return &People{Name: name,}
}// GetAge 获取age
func (people *People) GetAge() int {return people.age
}// SetAge 修改age
func (people *People) SetAge(age int) {people.age = age
}

通过工厂方法进行创建实例,age字段为私有,通过Setxxx、Getxxx方法首字母大写进行开放调用

Name为啥可以直接访问,因为首字母大写,是公共字段,可以在包外直接访问
在这里插入图片描述

不要觉得可以直接修改age,为啥还有加俩个方法,才进行修改age!封装的目的就是安全!

二、继承

子承父业,在现实社会中,我们通常进行各种学习,以达到自己冷暖自知的地步!

在代码中,上一个结构体抽象出了基本的属性和行为,但是相近的结构体也有大部分相同的属性和行为怎么办呢?需要在写一份相同的内容吗? 代码层面上,要做到简洁、高效!golang中解决重复代码的方法,就是继承!!!

1. 实现继承

在 Golang 中,如果一个 struct 嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现了继承特性。

package mainimport "fmt"type Goods struct {// 商品名称name string// 商品价格price float64
}type Book struct {// 继承GoodsGoods// 作者author string
}func main() {var book Book = Book{}book.name = "Go语言"book.price = 99.9book.author = "雨中散步撒哈拉"fmt.Println(book.name, book.price, book.author)// Go语言 99.9 雨中散步撒哈拉
}

商品的共性是有名称和价格,其中一种商品为书籍,也有其名称和售价,这时使用继承,进行匿名嵌套商品结构体,书籍具有了商品名称和价格的属性。

2. 继承的好处

  1. 代码的复用性提高了
  2. 代码的扩展性和维护性提高了

3. 继承的字段和方法

在我们进行继承的过程中,怎么知道我调用的是自己的属性/方法,还是上层的呢?

package mainimport "fmt"type Ball struct {// 球的材质material string// 价格price float64
}// GetBallInfo 获取球的信息
func (this *Ball) GetBallInfo() {fmt.Println("球的材质:", this.material, "价格:", this.price)
}// GetBallAddInfo 获取球地址生产信息
func (this *Ball) GetBallAddInfo() {fmt.Println("球的材质:", this.material, "价格:", this.price)
}type Basketball struct {// 继承BallBall// 球的尺寸size string
}// GetBallInfo 获取篮球信息
func (this *Basketball) GetBallInfo() {fmt.Println("篮球的材质:", this.material, "价格:", this.price)
}func main() {var ball Ball = Ball{}ball.material = "橡胶"ball.price = 99.9var basketball Basketball = Basketball{}basketball.material = "化学材质"basketball.price = 9.9basketball.size = "35"fmt.Println(basketball.material)// 化学材质fmt.Println(basketball.size)// 35basketball.GetBallInfo()// 篮球的材质: 化学材质 价格: 9.9basketball.GetBallAddInfo()// 球的材质: 化学材质 价格: 9.9}

球和篮球,俩个结构体都具有材质和价格属性、基本信息方法,篮球有尺寸属性,球有生产地址方法。

在调用过程中发现

  1. 属性:先看调用着自身是否有该字段,如果有,则用调用者自身属性,如果没有,则用继承的属性
  2. 方法:基本和属性一样,先找自己是否有,有则用自己的,无则用继承的方法

就近原则!

4. 多重继承

如一个 struct 嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承。

package mainimport "fmt"type Brand struct {// 名称Name string// 价格Price float64
}type Factory struct {// 工厂名称Name string// 地址Address string
}type FootBall struct {BrandFactory
}func main() {var footBall FootBall = FootBall{}// 设置品牌属性footBall.Brand.Name = "Nike"footBall.Price = 99.9// 设置工厂属性footBall.Factory.Name = "梦想工厂"footBall.Address = "北京"fmt.Println(footBall.Brand.Name, footBall.Price, footBall.Factory.Name, footBall.Address)// Nike 99.9 梦想工厂 北京
}

嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体类型名来
区分。

三、接口

多态的实现,需要借用接口进行扩展!这里先介绍下接口!

1. 接口说明

interface 类型可以定义一组方法,但是这些不需要实现。并且 interface 不能包含任何变量。到某个自定义类型要使用的时候,在根据具体情况把这些方法写出来(实现)。

2. 基本语法

type 接口名称 interface {mothod1(参数列表) 返回值列表mothod2(参数列表) 返回值列表
}
  1. 接口里的所有方法都没有方法体,即接口的方法都是没有实现的方法。接口体现了程序设计的多态和高内聚低偶合的思想。
  2. Golang 中的接口,不需要显式的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,Golang 中没有implement这样的关键字
  3. 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
  4. 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型
  5. 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
  6. 一个自定义类型可以实现多个接口
  7. Golang 接口中不能有任何变量
  8. 一个接口(比如 A 接口)可以继承多个别的接口(比如 B.C接口),这时如果要实现 A接口,也必须将 B.C接口的方法也全部实现。
  9. interface 类型默认是一个指针(引用类型),如果没有对 interface 初始化就使用,那么会输出 nil
  10. 空接口 interface{}没有任何方法,所以所有类型都实现了空接口,即我们可以把任何一个变量赋给空接口。
package mainimport "fmt"type EnglishSkills interface {// SayEnglish 说英语SayEnglish()
}type Student struct {// 姓名name string
}func (this *Student) SayEnglish() {fmt.Println("Student:", this.name, "SayEnglish")
}func main() {var student Student = Student{}student.name = "张三"student.SayEnglish()// Student: 张三 SayEnglish
}

四、多态

现实世界中,看到一条狗,我们既可以叫它狗,也可以叫它动物!这种现象是生物界繁衍产生的!

那代码世界呢?我如何表达狗,也可以叫做动物呢?中间的关系纽带是什么呢?
答案就是上边刚学到的–接口!

package mainimport "fmt"// Animal 动物
type Animal interface {// Smell 嗅觉灵敏Smell()
}// Dog 狗
type Dog struct {Name string
}// Smell 嗅觉灵敏  Dog进行实现
func (a *Dog) Smell() {fmt.Println("狗的嗅觉很灵敏...")
}// Cat 猫
type Cat struct {Name string
}// Smell 嗅觉灵敏  Dog进行实现
func (a *Cat) Smell() {fmt.Println("猫的嗅觉很灵敏...")
}

Dog/Cat结构体如果全部实现了接口Animal方法,那么Dog/Cat就实现Animal接口!

1. 多态参数

在传递参数的过程中,形参可以使用接口的类型进行传递参数。

// animalSmell 多态参数
func (this *Cat) animalSmell(animal Animal) {animal.Smell()
}func main() {cat := Cat{}dog := Dog{}// 传入不同的实现类型cat.animalSmell(&cat)// 输出:猫的嗅觉很灵敏...cat.animalSmell(&dog)// 输出:狗的嗅觉很灵敏...
}

animalSmell方法形参为Animal,实参为实现了Animal接口的结构体实例,输出结果是传入实例的方法输出!

接口是模板,结构体是样品,多态就是按模板造出不同却兼容的样品。

2. 多态数组

结构体在创建对象的过程中,后边是各种结构体,前边则是实现的接口类型,这种现象为多态!是编程语言扩展功能的方式!

var animal Animal = &Cat{}

如果把上边多个创建对象合并到一个数组中,则为多态数组,其实看懂上边这一行就行!!!

	var animalArr [3]AnimalanimalArr[0] = &Cat{"小白"}animalArr[1] = &Dog{"二哈"}animalArr[2] = &Cat{"小黑"}fmt.Println(animalArr)

3. 类型断言

由多态延申过来,多态过程中,判断接口接收到的当前对象,是否为想要的类型!如果是则条件成立,如果否则条件失败!

	// 结构体Dog 实例化后,使用Animal接口接收var dog2 Animal = &Dog{}// 判断是否为Dog类型d := dog2.(*Dog)fmt.Printf("%T, %v\n", d, d)// *main.Dog, &{}// 声明空接口xvar x interface{}// 赋值fvar f float32 = 3.14// 变量f  赋值给空接口xx = f// 判断x是否为float64var ff = x.(float64)// 抛出异常// panic: interface conversion: interface {} is float32, not float64

多态过程中:判断接口是否为某一个类型,而进行的判断

本篇进行介绍了面向对象的三大特性:封装、继承、多态

其中多态,需要使用接口的概念来进行实现,进而达到扩展的作用!

三大特性在开发过程中,经常用到,需要熟练使用,达到举一反三的目的!

http://www.dtcms.com/a/597142.html

相关文章:

  • Java 不同创建线程的方式什么时候才可以使用 this 来获取线程的引用
  • 兰州做网站的公司wordpress标签云美化
  • MATLAB基于PSO-GA的铁路工程施工进度计划多目标优化研究
  • JavaScript的BOM学习笔记——1、浏览器对象模型
  • python将Excel数据写进图片中
  • 五金配件网站建设报价圣弓 网站建设
  • Django中如何重写save()方法
  • C在线编程 | 提升编程技能,掌握C语言的核心要点
  • 京东这样的网站怎么做网站建设费用怎么算
  • django模型数据查询
  • 佛山骏域网站建设软件开发价格标准
  • discuz企业网站一诺摄影设计
  • 基于微信小程序的特色农产品交易系统
  • 【windows常见问题】pin不可用,无法登录Windows
  • 免费正能量励志网站网站登陆界面怎么做
  • 网站建设找丿金手指排名在iis上部署的网站本机无法浏览解决方法
  • 【Android Studio】解决4K电视机上,网页无法适配的问题
  • 如何选择适合自动化的测试用例?
  • 一步一步网站建设教程联通 网站备案
  • 著名心理学导师钧岚确认出席2025厦门IP+AI万人峰会​
  • 10.游戏逆向-pxxx-UObjectBase成员解密
  • 触发器,存储过程
  • 计算点到三次 Bézier 曲线最短距离及对应参数 u 的方法(转化为五次多项式)
  • npm中-d -g 和默认安装的区别
  • 深圳商城网站建设报价单青岛网站建设的方案
  • AI 编程工具全景分析与 Claude Code 配置 MiniMax - m2 模型指南​
  • MES 生产调度模块:业务逻辑、功能细节与全场景落地
  • PG认证培训考试中心-CUUG【工信人才授权指定】
  • 研究院 网站建设云主机怎么装网站
  • 微网站模板代码电子商务实网站的建设课件