首页 > 其他分享 >go的封装、继承与多态的使用

go的封装、继承与多态的使用

时间:2023-12-20 14:56:07浏览次数:25  
标签:封装 string age 多态 Dog person go Name Speak

目录

一、封装

​ 在Go语言中,封装是一种将数据和操作数据的方法组织在一起的概念。封装的目的是隐藏数据的具体实现细节,只向外部提供有限的接口,以防止外部直接访问和修改内部数据,同时可以通过方法来操作这些数据。

1.1 公有封装

package main

import "fmt"

// Person 结构体表示一个人,公有字段可以直接访问
type Person struct {
	Name string
	Age  int
}

func main() {
	// 创建 Person 实例
	person := Person{Name: "John", Age: 30}

	// 直接访问公有字段
	fmt.Println("Name:", person.Name)
	fmt.Println("Age:", person.Age)
}

结果输出:

Name: John
Age: 30

1.2 私有封装

package main

import "fmt"

// person 结构体表示一个人,私有字段需要通过公有方法访问
type person struct {
	name string
	age  int
}

// NewPerson 是一个工厂函数,用于创建 person 实例
func NewPerson(name string, age int) *person {
	return &person{name: name, age: age}
}

// GetName 方法用于获取姓名
func (p *person) GetName() string {
	return p.name
}

// GetAge 方法用于获取年龄
func (p *person) GetAge() int {
	return p.age
}

func main() {
	// 使用工厂函数创建 person 实例
	p := NewPerson("John", 30)

	// 使用公有的方法获取私有字段的值
	fmt.Println("Name:", p.GetName())
	fmt.Println("Age:", p.GetAge())
}

结果输出:

Name: John
Age: 30

1.2.1 工厂函数解析

工厂函数是一种用于创建并返回结构体实例的函数。与普通的结构体实例创建方法不同,工厂函数可以进行一些额外的逻辑,如参数验证、初始化等,并且通常返回指向结构体实例的指针。

【工厂函数】

goCopy code// NewPerson 是一个工厂函数,用于创建 person 实例
func NewPerson(name string, age int) *person {
	return &person{name: name, age: age}
}

在这里,NewPerson 函数接受 nameage 作为参数,执行了结构体 person 的实例化操作,并返回指向该实例的指针。

【普通的结构体与函数绑定】

goCopy codetype Person struct {
	name string
	age  int
}

// 创建一个新的 Person 实例
func CreatePerson(name string, age int) Person {
	return Person{name: name, age: age}
}

在这里,我们直接在 CreatePerson 函数内部实例化 Person 结构体,并返回该结构体实例。这是一种直接创建结构体实例的方法,没有使用指针。

1.2.2 &与*指针使用描述

func (p *person) GetAge() int {
	return p.age
}

(p *person) 描述

  • (p *person) 是一个接收者(receiver)声明,出现在方法定义中,这个接收者声明指定了方法所属的类型,以及方法可以通过什么方式调用
  • (p *person) 表示这个方法属于 person 结构体类型
  • p 是参数名,表示在方法内部可以使用 p 这个名字引用调用该方法的结构体实例。
  • *person 表示这个方法属于 person 结构体的指针类型。

当调用一个指针接收者的方法时,Go 语言会隐式地将指向结构体的实例的地址传递给这个方法。你可以直接传递结构体实例的地址,而不需要显式地取地址(使用 & 操作符)。

例如,在下面的代码中,调用 p.GetAge() 方法时,你可以传递 p&p,Go 语言会在底层进行处理:

goCopy code
age := p.GetAge()  // 传递 p,不需要取地址

或者:

goCopy code
age := (&p).GetAge()  // 传递 &p,可以显式取地址

这两者是等效的。Go 语言会自动将 p 转换为 &p,以适应指针接收者的方法的调用。

1.3 深度封装

package main

import "fmt"

// person 结构体表示一个人,私有字段需要通过公有方法访问
type person struct {
	name string
	age  int
}

// NewPerson 是一个工厂函数,用于创建 person 实例
func NewPerson(name string, age int) *person {
	return &person{name: name, age: age}
}

// GetName 方法用于获取姓名
func (p *person) GetName() string {
	return p.name
}

// GetAge 方法用于获取年龄
func (p *person) GetAge() int {
	return p.age
}

// Student 结构体表示一个学生,嵌套了 person 结构体
type Student struct {
	person  // 嵌套 person 结构体
	studentID string
}

// NewStudent 是一个工厂函数,用于创建 Student 实例
func NewStudent(name string, age int, studentID string) *Student {
	return &Student{
		person:   person{name: name, age: age},
		studentID: studentID,
	}
}

// GetStudentID 方法用于获取学生ID
func (s *Student) GetStudentID() string {
	return s.studentID
}

func main() {
	// 使用工厂函数创建 Student 实例
	student := NewStudent("Alice", 20, "12345")

	// 使用公有的方法获取字段的值
	fmt.Println("Name:", student.GetName())
	fmt.Println("Age:", student.GetAge())
	fmt.Println("Student ID:", student.GetStudentID())
}

在这个示例中,Student 结构体嵌套了 person 结构体,通过这种方式,Student 类型可以访问 person 类型的公有方法和字段。这展示了深度封装的概念,其中一个结构体嵌套了另一个结构体。

二、继承与多态

  • ​ 在 Go 语言中并没有传统面向对象语言中的类和继承的概念。
  • ​ Go 语言通过组合和接口实现代码复用和多态。
  • ​ 可以通过嵌入其他结构体来实现类似继承的效果。这被称为组合。同时,通过接口,你可以实现多态性(多态(Polymorphism)是指通过统一的接口来实现对不同类型对象的统一操作)。

2.1 继承与多态案例

package main

import "fmt"

// Animal 接口定义了一个通用的动物行为
type Animal interface {
	Speak() string
}

// Dog 结构体代表了一个狗,嵌入了 Animal 接口(因为下面func (d Dog) Speak() string{}关系)
type Dog struct {
	Name string
}

// Speak 是 Dog 结构体实现的 Animal 接口的方法
func (d Dog) Speak() string {
	return "Woof!"
}

// Cat 结构体代表了一个猫,嵌入了 Animal 接口
type Cat struct {
	Name string
}

// Speak 是 Cat 结构体实现的 Animal 接口的方法
func (c Cat) Speak() string {
	return "Meow!"
}

func main() {
	// 使用 Dog 结构体
	dog := Dog{Name: "Buddy"}
	// 使用 Cat 结构体
	cat := Cat{Name: "Whiskers"}

	// 调用 Speak 方法,无论是狗还是猫,它们都符合 Animal 接口的定义
	fmt.Println(dog.Name, "says:", dog.Speak())
	fmt.Println(cat.Name, "says:", cat.Speak())
}

2.1.1 继承代码分析

通过定义Dog结构体

type Dog struct {
	Name string
}

与speak()方法进行绑定,func (d Dog) Speak() stringDog 结构体实现了 Animal 接口的 Speak 方法。这种方式被称为 接口方法的实现

func (d Dog) Speak() string {
	return "Woof!"
}

从而继承了Animal特征

type Animal interface {
	Speak() string
}

cat 解析如上一样的。

2.1.2 结构体实例化

	// 使用 Dog 结构体
	dog := Dog{Name: "Buddy"}

dog.Name 意思:

在dog := Dog{Name: "Buddy"}这行代码中,我们创建了一个Dog类型的实例,通过使用结构体字面量给 Name 字段赋值为 "Buddy"。然后,我们用 dog 变量来引用这个新创建的实例。因为 Name 字段是公共字段,所以我们可以通过 dog.Name 来获取并访问这个字段的值。这种方式是通过结构体实例的字段名来访问其属性。

dog.Speak()意思:

通过 Dog{Name: "Buddy"} 实例化后,得到的 dog 变量是 Dog 结构体类型的实例。由于 Speak 方法是与 Dog 结构体绑定的方法,因此我们可以通过这个实例直接调用 Speak 方法,如 dog.Speak()。这是 Go 语言中一种通过实例调用与其类型绑定的方法的常见方式。

2.1.3 多态代码分析

DogCat 结构体都实现了 Animal 接口,通过 Animal 接口的 Speak 方法,可以对不同类型的对象进行相同的操作。

具体来说,在以下代码中体现了多态代码:

goCopy code// Animal 接口定义了一个 Speak 方法
type Animal interface {
	Speak() string
}

// ...

func main() {
	// 使用 Dog 结构体
	dog := Dog{Name: "Buddy"}
	// 使用 Cat 结构体
	cat := Cat{Name: "Whiskers"}

	// 调用 Animal 接口中的 Speak 方法
	fmt.Println("Dog says:", dog.Speak())
	fmt.Println("Cat says:", cat.Speak())
}

在这个案例中,多态体现在 Animal 接口上。DogCat 结构体都实现了 Animal 接口,它们分别定义了自己的 Speak 方法。在 main 函数中,我们创建了 dogcat 两个实例,并通过 Animal 接口调用了它们的 Speak 方法。这种情况下,编译器会根据实际的类型来调用相应的 Speak 方法,即使是通过相同的接口进行调用。

标签:封装,string,age,多态,Dog,person,go,Name,Speak
From: https://www.cnblogs.com/NGU-PX/p/17916522.html

相关文章

  • 接口自动化之响应数据封装
    在使用requests实现接口自动化时,接口响应的数据没有代码提示,要获取某个接口字段就需要通过[xxx]的方式来获取,实际开发过程中希望能通过.的方式来获取到某个接口响应属性。方式一、使用dataclassdataclass是python3.7新推出的特性之一fromdataclassesimportdataclass@......
  • 无涯教程-Go - Range(范围)
    Range关键字在for循环中使用,以迭代数组,切片,通道或映射的项。Range关键字在for循环中使用,以迭代数组(Array),切片(Slice),通道(Channel)或映射(Map)的项,对于数组和切片,它以整数形式返回元素的索引。对于Map,它返回下一个键值对(key/value)的键(key)。Range范围返回一个或两个值,如......
  • 无涯教程-Go - Slice(切片)
    GoSlice是GoArray的抽象,GoArray数组允许您定义可容纳相同种类的变量,但是它不提供任何内置方法来动态增加其大小或获取其自身的子数组。Slice切片克服了此限制,它提供了Array数组所需的许多实用程序功能,并广泛用于Go编程中。定义切片要定义Slice切片,可以将其声明为数组,而无需......
  • ReplaceGoogleCDN替换打不开的网页资源
    插件安装地址:ChromeFirefoxEdge背景在日常的网络浏览中,我们经常访问各种网站,其中包括大量使用了GoogleCDN(ContentDeliveryNetwork)的网页。虽然GoogleCDN在提供稳定、高效的内容分发方面表现出色,但在某些情况下,由于网络限制或其他原因,我们可能会遇到加载缓慢或无法访......
  • Why Choose Noregon JPRO Professional Diagnostic 2023 v3 Software?
     Welcometotheworldofautomotivediagnostics,whereprecisionmeetsefficiency.WiththeNoregonJPROProfessionalDiagnostic2023v3software,mechanics,technicians,andautomotiveenthusiastscanrevolutionizethewaytheyapproachvehiclediagnost......
  • MongoDB中如何优雅地删除大量数据
    删除大量数据,无论是在哪种数据库中,都是一个普遍性的需求。除了正常的业务需求,我们也需要通过这种方式来为数据库“瘦身”。为什么要“瘦身”呢?表的数据量到达一定量级后,数据量越大,表的查询性能相对也会越差。毕竟数据量越大,B+树的层级会越高,需要的IO也会越多。表的数据有......
  • 无涯教程-Go - 作用域
    任何编程中的作用域是程序中可以存在定义的变量并且不能访问该变量的区域,在三个地方可以使用Go编程语言声明变量-在函数或块内(local变量)所有函数之外(global变量)在函数参数中(formal参数)让我们找出什么是local和global变量以及什么是formal参数。局部变量在......
  • ArgoCD 添加私有仓库
    HTTPS方式访问私有仓库ArgoCDCLI添加私有仓库#argocdrepoaddhttps://github.com/argoproj/argocd-example-apps--username<username>--password<password>dashboard添加私有仓库SSHPrivateKeyCredentialArgoCDCLI添加known_hosts#ssh-keyscan-p3......
  • 无涯教程-Go - 常量类型
    常量是指程序在执行过程中不得更改的固定值。整数类型整数文字可以是十进制,八进制或十六进制常量,前缀指定基数或基数:十六进制为0x或0X,八进制为0,十进制为空。整数文字也可以具有后缀,该后缀是U和L的组合,分别表示无符号和长整数,后缀可以是大写或小写,并且可以是任何顺序。212......
  • GoFrame Goland插件
    前言GoFrame是一款模块化、高性能、企业级的Go基础开发框架。GoFrame是一款通用性的基础开发框架,是Golang标准库的一个增强扩展级,包含通用核心的基础开发组件,优点是实战化、模块化、文档全面、模块丰富、易用性高、通用性强、面向团队。GoFrame既可用于开发完整的工程化项......