Go语言基础 面向“对象”

结构体

Goland语言面向对象编程说明

1,Goland 也支持面向对象编程(OOP)但是和传统的面向对象编程有区别 并不是纯粹的面向对象语言 所以说Goland 支持面向对象编程的特性是比较准确的
2, Goland 没有类(class)Go 语言的结构体(struct)和其他编程语言的类(class)有同等地位 可以理解Goland 是基于struct 来实现OOP特性的
3,Goland 面向对象编程非常简洁 去掉了传统OOP 语言的继承 方法重载 构造函数和析构函数 隐藏的this 指针等等
4, Golang仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其它OOP语言不一样,比如继承:Golang没有extends关键字,继承是通过匿名字段来实现。
5, Golang面向对象(OOP)很优雅,OOP本身就是语言类型系统(type system)的一部分,通过接口(interface)关联,耦合性低,也非常灵活。后面同学们会充分体会到这个特点。也就是说在Golang中面向接口编程是非常重要的特性。

快速入门案例

package main

type Cat struct {
	Name  string
	age   int
	higth int
}

package main

import "fmt"

func main() {
	var cat Cat
	cat.age = 16
	cat.Name = "娇娇"
	cat.higth = 183

	fmt.Println(cat)
}


结构体和结构体变量(实例)的区别和联系

通过上面的案例可以看出:
1)结构体是自定义的数据类型,代表一类事物.
2)结构体变量(实例是具体的,实际的,代表一个具体变量

结构体的字段介绍

1)从概念或叫法上看:结构体字段=属性=field(即授课中,统一叫字段)
2)字段是结构体的一个组成部分,一般是基本数据类型、数组,也可是引用类型。比如我们前面定义猫结构体的 Name string就是属性

取值的方式

package main

import (
	"Test/Demo/StructDemo"
	"fmt"
)

func main() {
	// 方式一
	var cat Cat
	cat.age = 16
	cat.Name = "娇娇"
	cat.higth = 183

	fmt.Println(cat)
	// 方式二
	cat := StructDemo.Cat{Name: "娇娇", Age: 15, Id: 1}
	fmt.Println(cat)
	// 方式三
	cat1 := new(StructDemo.Cat)
	cat1.Id = 2
	cat1.Name = "小狗"
	cat1.Age = 1
	fmt.Println(cat1)

}

方法

基本介绍

在某些情况下,我们要需要声明(定义)方法。比如Person结构体:除了有一些字段外(年龄,姓名…)Person结构体还有一些行为比如:可以说话、跑步.,通过学习,还可以做算术题。这时就要用方法才能完成。
Golang中的方法是作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,T而不仅仅是struct

package StructDemo

import "fmt"

type Cat struct {
	Name string
	Age  int
	Id   int
}

//方法 绑定一个 Cat 结构体的方法 这个方法只能 通过Cat 类型的变量调用 不能直接调用或者其他类型调用
func (c Cat) CatTest() {
	fmt.Println(c)
}
package main

import (
	"Test/Demo/StructDemo"
)

func main() {
	// 方式二
	cat := StructDemo.Cat{Name: "娇娇", Age: 15, Id: 1}
	cat.CatTest()

}

入门案例

package StructDemo

import "fmt"

type Cat struct {
	Name string
	Age  int
	Id   int
}

//方法 绑定一个 Cat 结构体的方法 这个方法只能 通过Cat 类型的变量调用 不能直接调用或者其他类型调用
func (c Cat) Eat() {
	fmt.Println("小猫会吃饭....")
}
func (c Cat) Jisuan(a int, b int) int {
	return a + b
}
package StructDemo

import "fmt"

type Cat struct {
	Name string
	Age  int
	Id   int
}

//方法 绑定一个 Cat 结构体的方法 这个方法只能 通过Cat 类型的变量调用 不能直接调用或者其他类型调用
func (c Cat) Eat() {
	fmt.Println("小猫会吃饭....")
}
func (c Cat) Jisuan(a int, b int) int {
	return a + b
}
package main

import (
	"Test/Demo/StructDemo"
	"fmt"
)

func main() {
	// 方式二
	cat := StructDemo.Cat{Name: "娇娇", Age: 15, Id: 1}
	cat.Eat()
	jisuan := cat.Jisuan(10, 20)
	fmt.Println(jisuan)
}

方法的声明(定义)

fund (recevier type) methodName(参数列表)(返回值列表){
方法体
return返回值
}
1)参数列表:表示方法输入
2) recevier type:表示这个方法和type这个类型进行绑定,或者说该方法作用于type类型3) receiver type : type可以是结构体,也可以其它的自定义类型
4)receiver :就是type类型的一个变量(实例),比如:Person结构体的一个变量(实例)5)参数列表:表示方法输入
6)返回值列表:表示返回的值,可以多个7)方法主体:表示为了实现某一功能代码块)return语句不是必须的。

方法注意事项和细节讨论

1))结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
2)如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理
3) Golang中的方法作用在指定的数据类型上的(即:和指定的数据类型绑定),
因此自定义类型,都可以有方法,而不仅仅是strupt,比如int , float32等都可以有方法
4)方法的访问范围控制的规则,和函数一样。方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其它包访问。[讲解]
5)如果一个变量实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出

方法和函数区别

1)调用方式不一样
函数的调用方式:
函数名(实参列表)
方法的调用方式:
变量.方法名(实参列表)
2)对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
3)对于方法(如struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以

工厂模式

说明

Golang的结构体没有构造函数,通常可以使用工厂模式来解决这个问题。
看一个需求
一个结构体的声明是这样的:package model
type Student struct {Name string…
}
因为这里的student 的首字母s是大写的,如果我们想在其它包创建Student的实例(比如main包),引入model包后,就可以直接创建Student结构体的变量(实例)。但是问题来了,如果首字母是小写的,比如是type student struct {…}就不不行了,怎么办—>工厂模式来解决.

package model

import "fmt"

type cat struct {
	Name string
	Age  int
	Id   int
}

// 编写工厂模式
func NewCat(n string, a int, id int) *cat {
	return &cat{
		Name: n,
		Age:  a,
		Id:   id,
	}
}

package main

import (
	"Test/Demo/StructDemo/model"
	"fmt"
)

func main() {
	cat := model.NewCat("jiaojiao", 12, 22)
	fmt.Println(cat)
}

封装

封装介绍

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

封装的理解和好处

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

如何体现封装

1)对结构体中的属性进行封装
2)通过方法,包实现封装封装的实现步骤
1)将结构体、字段(属性)的首字母小写(不能导出了,其它包不能使用,类似private)2)给结构体所在包提供一个工厂模式的函数,首字母大写。类似一个构造函数
3)提供一个首字母大写的set方法(类似其它语言的public),用于对属性判断并赋值
func (var结构体类型名) SetXxx(参数列表)(返回值列表){
//加入数据验证的业务逻辑
var.字段=参数
4)提供一个首字母大写的Get方法(类似其它语言的public),用于获取属性的值
func (var结构体类型名)GetXxx() {
return var.age;
}

面向对象编程-继承继承基本介绍和示意图

继承可以解决代码复用,让我们的编程更加靠近人类思维。
当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体(比如刚才的Studerlt),在该结构体中定义这些相同的属性和方法。
其它的结构体不需要重新定义这些属性和方法,只需嵌套一个student匿名结构体即可。[画出示意图]
也就是说:在Golang中,如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现了继承特性。

嵌套匿名结构体的基本用法


type Person1 struct {
	Name string
	age  int
	
}
type Son struct {
	Person1
	address string
}

多重继承

多重继承说明

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

接口

在这里插入图片描述

入门案例

package main

import "fmt"

// 定义一个接口 (提供两个方法)我这里是提供了充电的
type Usb interface {
	Start()
	Stop()
}

// 创建安卓手机的结构体
type An struct {
}

func (a An) Start() {
	fmt.Println("安卓手机开始充电")
}
func (a An) Stop() {
	fmt.Println("安卓手机结束充电")
}

// 创建ios 结构体
type Ios struct {
}

func (a Ios) Start() {
	fmt.Println("Ios手机开始充电")
}
func (a Ios) Stop() {
	fmt.Println("Ios手机结束充电")
}

// 创建插座的
type Cha struct {
}

func (c Cha) Get(usb Usb) {
	usb.Stop()
	usb.Start()
}

func main() {
	cha := Cha{}
	ios := Ios{}
	an := An{}
	cha.Get(ios)
	cha.Get(an)

}
/home/work/apps/go/bin/go build -o /tmp/GoLand/___go_build_Test_Demo_interface_main Test/Demo/interface/main #gosetup
/tmp/GoLand/___go_build_Test_Demo_interface_main
Ios手机结束充电
Ios手机开始充电
安卓手机结束充电
安卓手机开始充电

在这里插入图片描述

注意事项

1, 接口本身不能创建实例 但是可以指向一个实现改接口的自定义类型的变量(实例)
2,接口中所有的方法都没有方法体 即搜没有实现的方法
3,在Golang 中 一个自定义类型需要将某个接口的所有方法都实现 我们说这个自定义类型实现了该接口
4, 一个自定义类型只有实现了某个接口 才能将该自定义类型的实力(变量)赋给接口类型
5 只要是自定义数据类型就可以实现接口 不仅仅是结构体类型

接口跟继承的区别

1 当A 结构体继承B结构体 那么A结构就自动的继承了B结构体的字段和方法 并且可以直接使用
2, 当A 结构体需要扩展功能 同时不希望去破坏继承关系 则可以实现某个接口即可 因此我们可以认为:实现接口是对继承机制的补充

接口(interface)实现接口vs继承

1,接口和继承解决的解决的问题不同
继承的价值主要在于:解决代码的复用性和可维护性。
接口的价值主要在于:设计,设计好各种规范(方法),让其它自定义类型去实现这些方法。
2接口比继承更加灵活
接口比继承更加灵活,继承是满足is - a的关系,而接口只需满足 like - a的关系。
3 接口在一定程度上实现代码解耦

多态

基本介绍

变量(实例)具有多种形态。面向对象的第三大特征,在Go语言,多态特征是通过接口实现的。可以按照统一的接口来调用不同的实现。这时接口变量就呈现不同的形态。

快速入门

在前面的usb接口案例,Usb usb,既可以接收手机变量,又可以接收相机变量,就体现了usb接口多态特性。这个接口就体现了类的多种状态。 这个Usb 接口会根据传入的实参 来判断是IOS 还是安卓

package main

import "fmt"

// 定义一个接口 (提供两个方法)我这里是提供了充电的
type Usb interface {
	Start()
	Stop()
}

// 创建安卓手机的结构体
type An struct {
}

func (a An) Start() {
	fmt.Println("安卓手机开始充电")
}
func (a An) Stop() {
	fmt.Println("安卓手机结束充电")
}

// 创建ios 结构体
type Ios struct {
}

func (a Ios) Start() {
	fmt.Println("Ios手机开始充电")
}
func (a Ios) Stop() {
	fmt.Println("Ios手机结束充电")
}

// 创建插座的
type Cha struct {
}

func (c Cha) Get(usb Usb) {
	usb.Stop()
	usb.Start()
}

func main() {
	cha := Cha{}
	ios := Ios{}
	an := An{}
	cha.Get(ios)
	cha.Get(an)

}

接口体现多态的两种形式

1 多态参数
在前面的Usb接口案例,Usb usb ,即可以接收手机变量,又可以接收相机变量,就体现了Usb接口多态。
多态数组
演示一个案例:给Usb数组中,存放 Phone结构体和Camera结构体变量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值