10-Go基础:面向对象

一、面向对象简介

  • 面向过程概念:所谓的面向过程就是 -> 强调的是步骤、过程、每一步都是自己亲自去实现的
  • 面向对象概念:所谓的面向对象其实就是找一个专门做这个事的人来做,不用关心具体怎么实现的
  • 面向对象和面向过程区别:面向过程强调的是过程,步骤。而面向对象强调的是对象,也就是干事的人
  • 编程中描述类:在程序中,可以通过属性和方法(函数)来描述类。属性就是特征,方法(函数)就是行为

二、继承

1 - 通过匿名字段来实现继承

  • 继承概念
    • 继承是一种类间关系,描述一个类从另一个类获取成员信息的类间关系
    • 继承必定发生在两个类之间,参与继承关系的双方称为父类和子类
    • 父类提供成员信息,子类获取成员信息
  • 匿名字段实现继承与初始化
type Student struct {
	Person // 匿名字段,,只有类型,没有成员的名字
	score  float64
}
type Teacher struct {
	Person
	salary float64
}
type Person struct {
	id   int
	name string
	age  int
}

func main() {
	var stu Student = Student{Person{101, "张三", 18}, 90}
	// 部分初始化
	var stu1 Student = Student{score: 90}
	var stu2 Student = Student{Person: Person{id: 101}}
	fmt.Println(stu)  // {{101 张三 18} 90}
	fmt.Println(stu1) // {{0  0} 90}
	fmt.Println(stu2) // {{101  0} 0}
}

2 - 成员操作

  • 成员的操作包含
    • 获取成员的值:对象名.成员
    • 修改成员的值:对象名.成员 = 值
type Student struct {
	Person
	score float64
}
type Person struct {
	id   int
	name string
	age  int
}

func main() {

	var stu Student = Student{Person{101, "张三", 18}, 90}
	var stu1 Student = Student{Person{102, "李四", 18}, 80}
	stu.score = 100
	fmt.Println("张三考试成绩:", stu.score)
	fmt.Println(stu1.score)
	fmt.Println(stu1.Person.id)
	fmt.Println(stu1.id) //简化写法,先到子类中查找成员,没有找到成员后就到父类中查找
}

3 - 指针匿名字段

type Student struct {
	*Person // 匿名字段
	score   float64
}
type Person struct {
	id   int
	name string
	age  int
}

func main() {
	var stu Student = Student{&Person{101, "张三", 18}, 90}
	fmt.Println(stu.name)
}

4 - 多重继承

type Student struct {
	Person
	score float64
}
type Person struct {
	Object
	name string
	age  int
}
type Object struct {
	id int
}

func main() {
	var stu Student
	stu.age = 18
	fmt.Println(stu.Person.age)
	stu.id = 101
	fmt.Println(stu.Person.Object.id)
}

5 - 为结构体添加方法

  • 一般都将方法的接收对象使用结构体指针来接收
//语法
func  (对象 结构体类型) 方法名 (参数列表)(返回值列表) {
		代码体
}

//案例
type Student struct {
	id   int
	name string
	age  int
}

func (s Student) PrintShow() {
	fmt.Println(s)
}
func (s *Student) EditInfo() {//如果不是结构体指针,将无法修改原对象的值
	s.age = 20
}
func main() {
	stu := Student{101, "张三", 18}
	stu.PrintShow() // 完成对方法的调用, 将stu中的值,传递给了方法的s
	stu.EditInfo()
	stu.PrintShow()
}
  • 只要接收者类型不一样,这个方法就算同名,也是不同方法
type Student struct {
	id   int
	name string
	age  int
}
type Teacher struct {
	id   int
	name string
}

func (s *Student) Show() {
	fmt.Println(s)
}
func (t *Teacher) Show() {
	fmt.Println(t)
}
func main() {
	// 如果接收者类型不同,即使方法的名字是相同的也是不同的方法
	stu := Student{101, "李四", 18}
	(&stu).Show()
	stu.Show() // 这个是go语言的优化,实际是(&stu).Show()
	teacher := Teacher{102, "老王"}
	teacher.Show()
}
  • 案例:获取学生信息
//定义一个学生类,有六个属性,分别为姓名、性别、年龄、语文、数学、英语成绩
//第一方法:打招呼的方法:介绍自己叫XX,今年几岁了。是男同学还是女同学。
//第二个方法:计算总分与平均分的方法

// 1: 定义结构体
type StudentInfo struct {
	name    string
	sex     string
	age     int
	chinese float64
	math    float64
	english float64
}

// 2: 添加方法
func (s *StudentInfo) SayHello(userName string, userAge int, userSex string) {
	// 2.1 初始化
	s.name = userName
	s.age = userAge
	s.sex = userSex
	// 2.2  初始化后的值进行判断。
	if s.sex != "男" && s.sex != "女" {
		s.sex = "男"
	}
	if s.age < 1 || s.age > 100 {
		s.age = 18
	}
	// 2.3 打印输出结果
	fmt.Printf("我叫%s,年龄是%d,性别是%s\n", s.name, s.age, s.sex)
}
func (s *StudentInfo) GetScore(chinese float64, math float64, english float64) {
	// 1: 初始化
	s.chinese = chinese
	s.math = math
	s.english = english
	// 2: 进行计算
	sum := s.chinese + s.math + s.english
	// 3: 打印输出结果
	fmt.Printf("我叫%s,总分%f,平均分%f", s.name, sum, sum/3)
}
func main() {
	var stu StudentInfo
	stu.SayHello("张三", 180, "df")
	stu.GetScore(90, 89, 87)
}

三、方法继承与重写

  • 方法继承:子类可以调用父类的方法
type Student struct {
	Person
	score float64
}
type Person struct {
	id   int
	name string
	age  int
}

func (p *Person) PrintInfo() {
	fmt.Println(*p)
}

func main() {
	stu := Student{Person{101, "张三", 18}, 90}
	stu.PrintInfo()
}
  • 方法重写:默认调用的是子类中的方法
    • 如果父类中的方法名称与子类中的方法名称一致,那么通过子类的对象调用的是子类中的方法
    • 子类方法重写,要调用父类的方法stu.Person.PrintInfo()
type Person struct {
	name string
	age  int
}

func (p *Person) PrintInfo() {
	fmt.Println("这是父类中的方法")
}

type Student struct {
	Person
	score float64
}

func (p *Student) PrintInfo() {
	fmt.Println("这是子类中的方法")
}

func main() {
	var stu Student
	stu.PrintInfo() // 如果父类中的方法名称与子类中的方法名称一致,那么通过子类的对象调用的是子类中的方法;方法重写
	stu.Person.PrintInfo()
}
  • 方法值与方法表达式:实现方法调用
type Person struct {
	name string
	age  int
}

func (p *Person) PrintInfo() {
	fmt.Println(*p)
}

func main() {
	per := Person{"张三", 18}
	per.PrintInfo()

	//方法值
	f := per.PrintInfo
	fmt.Printf("%T", f)
	f()

	//方法表达式
	f1 := (*Person).PrintInfo
	f1(&per)
}

四、接口

  • 什么是接口
    • 接口就是一种规范与标准,只是规定了要做哪些事情。具体怎么做,接口是不管的
    • 接口把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口
  • 接口定义语法
type 接口名字  interface {
	方法声明
}
  • 接口实现与调用
type Personer interface {
	SayHello()
}
type Student struct {
}

func (s *Student) SayHello() {
	fmt.Println("老师好")
}

type Teacher struct {
}

func (t *Teacher) SayHello() {
	fmt.Println("学生好")
}

func main() {
	// 对象名.方法名
	var stu Student
	stu.SayHello()
	var teacher Teacher
	teacher.SayHello()
	// 通过接口变量来调用,必须都实现接口中所声明的方法

	var person Personer
	person = &stu
	person.SayHello() // 调用的是Student 实现的SayHello方法
	person = &teacher
	person.SayHello()
}

五、多态

  • 多态概念:指的是多种表现形式;多态就是同一个接口,使用不同的实例而执行不同操作
  • 多态实现语法:定义函数实现
func 函数名 (参数 接口类型){
	
}
  • 多态定义与实现
type Personer interface {
	SayHello()
}
type Student struct {
}

func (s *Student) SayHello() {
	fmt.Println("老师好")
}

type Teacher struct {
}

func (t *Teacher) SayHello() {
	fmt.Println("学生好")
}

func WhoSayHi(h Personer) {
	h.SayHello()
}

func main() {
	var stu Student
	var teacher Teacher
	WhoSayHi(&stu)
	WhoSayHi(&teacher)
}
  • 案例:移动硬盘或者U盘插到电脑上进行读写数据
type Stroager interface {
	Read()
	Writer()
}

// 移动硬盘
type MDisk struct {
}

func (m *MDisk) Read() {
	fmt.Println("移动硬盘读取数据")
}
func (m *MDisk) Writer() {
	fmt.Println("移动硬盘写入数据")
}

// U盘
type UDisk struct {
}

func (u *UDisk) Read() {
	fmt.Println("U盘读取数据")
}
func (u *UDisk) Writer() {
	fmt.Println("U盘写入数据")
}

// 定义一个函数
func Computer(c Stroager) {
	c.Read()
	c.Writer()
}
func main() {
	var udisk UDisk
	var mdisk MDisk
	Computer(&udisk)
	Computer(&mdisk)
}
  • 案例:定义一个类实现计算器
type Object struct {
}

// 2: 添加一个方法。
func (o *Object) GetResult(numA int, numB int, op string) int {
	// 1: 添加参数
	// 2: 判断运算方式
	var result int
	switch op {
	case "+":
		result = numA + numB + 100
	case "-":
		result = numA - numB - 100
	}
	return result
}

func main() {
	var obj Object
	num := obj.GetResult(8, 6, "-")
	fmt.Println(num)
}
  • 案例:分离类方式实现计算器
// 加法类
type Add struct {
	Object
}

func (a *Add) GetResult() int { // 方法的实现要和接口中方法的声明保持一致
	return a.numA + a.numB
}

// 减法类
type Sub struct {
	Object
}

func (s *Sub) GetResult() int {
	return s.numA - s.numB
}

type Object struct {
	numA int
	numB int
}
type Resulter interface {
	GetResult() int
}

func main() {
	add := Add{Object{10, 20}}
	num := add.GetResult()
	fmt.Println(num)

	sub := Sub{Object{20, 10}}
	num1 := sub.GetResult()
	fmt.Println(num1)
}
  • 案例:工厂创建对象方式实现计算器
// 加法类
type Add struct {
	Object
}

func (a *Add) GetResult() int { // 方法的实现要和接口中方法的声明保持一致
	return a.numA + a.numB
}

// 减法类
type Sub struct {
	Object
}

func (s *Sub) GetResult() int {
	return s.numA - s.numB
}

type Object struct {
	numA int
	numB int
}
type Resulter interface {
	GetResult() int
}

// 对象问题
// 1: 定义一个新的类
type OperatorFactory struct {
}

// 2: 创建一个方法,在该方法中完成对象的创建
func (o *OperatorFactory) CreateOperator(op string, numA int, numB int) int {
	switch op {
	case "+":
		add := Add{Object{numA, numB}}
		return OperatorWho(&add)
	case "-":
		sub := Sub{Object{numA, numB}}
		return OperatorWho(&sub)
	default:
		return 0
	}
}
func OperatorWho(h Resulter) int {
	return h.GetResult()
}

func main() {
	var operator OperatorFactory
	num := operator.CreateOperator("-", 20, 10)
	fmt.Println(num)
}

六、接口的继承与转换

type Humaner interface {
	SayHello()
}
type Personer interface {
	Humaner
	Say()
}
type Student struct {
}

func (s *Student) SayHello() {
	fmt.Println("大家好")
}
func (s *Student) Say() {
	fmt.Println("你好")
}
func main() {
	var stu Student
	var per Personer
	per = &stu
	per.Say()
	per.SayHello() // 可以调用所继承的接口中的方法

	var h Humaner
	h = per
	h.SayHello()
}

七、空接口与类型断言

  • 空接口概念:空接口(interface{})不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型的数值
  • 定义与使用空接口
func main() {
	var i interface{} // i就是一个空接口类型的变量
	i = 123
	i = "abc"
	fmt.Println(i)
	var s []interface{} // 空接口类型的切片
	s = append(s, 123, "abc", 12.3)
	for j := 0; j < len(s); j++ {
		fmt.Println(s[j])
	}
}
  • 类型断言:通过类型断言,可以判断空接口中存储的数据类型
  • 类型断言语法value, ok := m.(T)
    • m:表空接口类型变量
    • T:是断言的类型.
    • value: 变量m中的值
    • ok: 布尔类型变量,如果断言成功为true,否则为false
func main() {
	var i interface{}
	i = "abc"
	value, ok := i.(int)
	if ok {
		fmt.Println(value + 10)
	} else {
		fmt.Println("类型推断错误")
	}
}
  • 案例:空接口与类型断言实现计算器数据校验
package main

import "fmt"

// 加法类
type Add struct {
	Object
}

func (a *Add) GetResult() int { // 方法的实现要和接口中方法的声明保持一致
	return a.numA + a.numB
}
func (a *Add) SetData(data ...interface{}) bool {
	// 1: 对数据的个数进行校验。
	var b bool = true
	if len(data) > 2 {
		fmt.Println("参数个数错误!!")
		b = false
	}
	value, ok := data[0].(int)
	if !ok {
		fmt.Println("第一个数类型错误")
		b = false
	}
	value1, ok1 := data[1].(int)
	if !ok1 {
		fmt.Println("第二个数据类型错误")
		b = false
	}
	a.numA = value
	a.numB = value1
	// 2: 类型进行校验。
	return b
}

// 减法类
type Sub struct {
	Object
}

func (s *Sub) GetResult() int {
	return s.numA - s.numB
}

func (s *Sub) SetData(data ...interface{}) bool {
	// 1: 对数据的个数进行校验。
	var b bool = true
	if len(data) > 2 {
		fmt.Println("参数个数错误!!")
		b = false
	}
	value, ok := data[0].(int)
	if !ok {
		fmt.Println("第一个数类型错误")
		b = false
	}
	value1, ok1 := data[1].(int)
	if !ok1 {
		fmt.Println("第二个数据类型错误")
		b = false
	}
	s.numA = value
	s.numB = value1
	// 2: 类型进行校验。
	return b
}

type Object struct {
	numA int
	numB int
}
type Resulter interface {
	GetResult() int
	SetData(data ...interface{}) bool // 完成参数运算的数据的类型校验。
}

// 对象问题
// 1: 定义一个新的类
type OperatorFactory struct {
}

// 2: 创建一个方法,在该方法中完成对象的创建
func (o *OperatorFactory) CreateOperator(op string) Resulter {
	switch op {
	case "+":
		add := new(Add)
		return add
	case "-":
		sub := new(Sub)
		return sub

	default:
		return nil
	}
}
func OperatorWho(h Resulter) int {
	return h.GetResult()
}
func main() {
	var operator OperatorFactory
	obj := operator.CreateOperator("-")
	b := obj.SetData(30, 10)
	if b {
		num := OperatorWho(obj)
		fmt.Println(num)
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无休止符

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值