go语言基础--面向对象杂谈

面向过程

所谓的面向过程就是:强调的是步骤、过程、每一步都是自己亲自去实现的。

面向对象

所谓的面向对象其实就是找一个专门做这个事的人来做,不用关心具体怎么实现的。

所以说,面向过程强调的是过程,步骤。而面向对象强调的是对象,也就是干事的人。

在程序中,可以通过属性和方法(函数)来描述类。属性就是特征,方法(函数)就是行为。

面向对象编程好处

封装

继承

多态

继承

继承是一种类间关系,描述一个类从另一个类获取成员信息的类间关系。

继承必定发生在两个类之间,参与继承关系的双方称为父类和子类。

父类提供成员信息,子类获取成员信息。

通过匿名字段来实现继承

go 复制代码
package main

import "fmt"

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{1, "张三", 18}, 98}
	fmt.Println(stu) //{{1 张三 18} 98}

	//部分初始化
	var stu1 Student = Student{score: 90}
	fmt.Println(stu1) //{{0  0} 90}

	var stu2 Student = Student{Person: Person{id: 101}} //{{101  0} 0}
	fmt.Println(stu2)
}

成员操作

go 复制代码
package main

import "fmt"

type Student struct {
	//属性---成员
	//方法---函数
	Person //匿名字段,只有类型,没有成员的名字

	score float64
}

type Person struct {
	id   int
	name string
	age  int
}

func main() {
	var stu Student = Student{Person{101, "张三", 18}, 98}
	var stu1 Student = Student{Person{102, "李四", 18}, 80}

	//获取成员的值
	fmt.Println(stu.score)      //98
	fmt.Println(stu1.score)     //80
	fmt.Println(stu1.Person.id) //102 //比较麻烦
	fmt.Println(stu1.id)        //102

	//修改成员的值
	stu.score = 100
	fmt.Println(stu.score) //100

}

指针类型匿名字段

go 复制代码
package main

import "fmt"

type Student struct {
	//属性---成员
	//方法---函数
	*Person //指针类型匿名字段

	score float64
}

type Person struct {
	id   int
	name string
	age  int
}

func main() {
	var stu Student = Student{&Person{101, "张三", 18}, 98}
	fmt.Println(stu)      //{0xc000054460 98} 父类输出的是结构体内存地址 只能使用成员操作了
	fmt.Println(stu.name) //张三
}

多重继承---尽量不要写多重继承

go 复制代码
package main

import "fmt"

// Student 学生继承person
type Student struct {
	//属性---成员
	//方法---函数
	Person //指针类型匿名字段

	score float64
}

// Person 父类 person继承object
type Person struct {
	Object1
	name string
	age  int
}

type Object1 struct {
	id int
}

func main() {

	var stu Student
	stu.age = 18
	fmt.Println(stu.Person.age) //18
	stu.id = 101
	fmt.Println(stu.Person.Object1.id)
}

为结构体添加方法---封装

go 复制代码
func  (对象 结构体类型) 方法名 (参数列表)(返回值列表) {
	
		代码体

}

方法调用

对象名.方法

//不支持重载,只要接收者类型不一样,这个方法就算同名,也是不同方法,不会出现重复定义函数的错误

go 复制代码
package main

import "fmt"

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

// PrintShow 方法 s为接收者
func (s Student) PrintShow() {
	fmt.Println(s) //{101 ziye 18}
}

func (s Student) EditInfo() {
	s.age = 20
}

func (s *Student) EditInfo1() {
	s.age = 20
}
func main() {
	stu := Student{101, "ziye", 18}
	//对象名.方法名 把stu中的值传给了s
	stu.PrintShow() //完成对方法的调用
	stu.EditInfo()  //不是引用传递,是值传递
	stu.PrintShow()
	//内部会进行转换
	stu.EditInfo1() //引用传递
	stu.PrintShow() //{101 ziye 20}
}

注意事项

只要接收者类型不一样,这个方法就算同名,也是不同方法

接收者为指针类型

go 复制代码
package main

import "fmt"

// Student
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() { //把teacher内存地址给到这里
	fmt.Println(t)
}
func main() {
	//如果接收者类型不同,即使方法的名字是相同的也是不同的方法
	stu := Student{101, "ziye", 18}
	stu.show() //等价于(&stu).show()
	teacher := Teacher{102, "ziyeye"}
	teacher.show()
}

面向对象方法练习

定义一个学生类,有六个属性,分别为姓名、性别、年龄、语文、数学、英语成绩

定义两个方法:

第一方法:打招呼的方法:介绍自己叫XX,今年几岁了。是男同学还是女同学。
第二个方法:计算总分与平均分的方法
go 复制代码
package main

import "fmt"

// Student
type StudentInfo struct {
	name    string  //姓名
	sex     string  //性别
	age     int     //年龄
	chinese float64 //语文
	math    float64 //数学
	english float64 //英语
}

// SayHello 打招呼
func (studentInfo *StudentInfo) SayHello(username string, userAge int, userSex string) {
	//初始化
	studentInfo.name = username
	studentInfo.age = userAge
	studentInfo.sex = userSex
	//初始化后的值进行判断
	if studentInfo.sex != "男" && studentInfo.sex != "女" {
		studentInfo.sex = "男"
	}

	if studentInfo.age < 1 || studentInfo.age > 100 {
		studentInfo.age = 18
	}
	//打印输出结果
	fmt.Printf("我叫%s,年龄是%d,性别是%s\n", studentInfo.name, studentInfo.age, studentInfo.sex)
}

// GetScore 计算平均分
func (studentInfo *StudentInfo) GetScore(chinese float64, math float64, english float64) {
	//初始化
	studentInfo.chinese = chinese
	studentInfo.math = math
	studentInfo.english = english
	//进行计算
	sum := studentInfo.chinese + studentInfo.math + studentInfo.english
	//打印输出结果
	fmt.Printf("我叫%s,总分%f,平均分%.2f\n", studentInfo.name, sum, sum/3)
}
func main() {
	var stu StudentInfo
	stu.SayHello("ziye", 18, "女")
	stu.GetScore(98, 97, 95)
}

方法继承

go 复制代码
package main

import "fmt"

// Student
type Student struct {
	Person
	score float64
}

type Person struct {
	id   int
	name string //姓名
	age  int    //年龄
}

func (p *Person) PrintInfo() {
	fmt.Println(*p) //{101 张三 18}
}

func main() {
	stu := Student{Person{101, "张三", 18}, 90}
	//子类可以调用父类的方法
	stu.PrintInfo()
}

方法继承的练习

根据以下信息,实现对应的继承关系

记者:我叫张三 ,我的爱好是偷拍,我的年龄是34,我是一个男狗仔。

程序员:我叫孙全,我的年龄是23,我是男生,我的工作年限是 3年。

go 复制代码
  package main

import "fmt"

// Person 定义父类
type Person struct {
	name string
	age  int
	sex  string
}

// SetValue 给父类添加方法
func (p *Person) SetValue(userName string, userAge int, userSex string) {
	p.name = userName
	p.age = userAge
	p.sex = userSex
}

// Rep 定义相应的子类 记者类
type Rep struct {
	Person
	Hobby string //爱好
}

// Pro 程序员类
type Pro struct {
	Person
	WorkYear int
}

// RepSayHello 给子类添加相应的信息
func (r *Rep) RepSayHello(Hobby string) {
	r.Hobby = Hobby
	fmt.Printf("我叫%s ,我的爱好是%s,我的年龄是%d,我是一个%s狗仔\n", r.name, r.Hobby, r.age, r.sex)
}

// ProSayHello 给子类添加相应的信息
func (p *Pro) ProSayHello(workYear int) {
	p.WorkYear = workYear
	fmt.Printf("我叫%s,我的年龄是%d,我是%s,我的工作年限是 %d年\n", p.name, p.age, p.sex, p.WorkYear)
}
func main() {
	var rep Rep
	rep.SetValue("ziye", 34, "男")
	rep.RepSayHello("偷拍")

	var pro Pro
	pro.SetValue("李四", 26, "男")
	pro.ProSayHello(3)

}

方法重写

就是子类(结构体)中的方法,将父类中的相同名称的方法的功能重新给改写了

注意:在调用时,默认调用的是子类中的方法

go 复制代码
package main

import "fmt"

// Person 定义父类
type Person struct {
	name string
	age  int
}

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

type Student struct {
	Person
	score float64
}

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

func main() {
	var stu Student
	stu.PrintInfo() //这是子类中的方法 如果父类中的方法名称与子类中的方法一致,那么通过子类的对象调用的是子类中的方法,方法重写
	stu.Person.PrintInfo() //这是父类中的方法 调用父类中的方法
}

方法值与方法表达式

go 复制代码
package main

import "fmt"

// Person 定义父类
type Person struct {
	name string
	age  int
}

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

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

	//方法值
	f := per.PrintInfo
	fmt.Printf("%T\n", f) //func() 方法类型
	f()                   //{ziye 18}

	//方法表达式
	f1 := (*Person).PrintInfo //并没有指定一个对象 类名要和方法接收者类型保存一致
	f1(&per)                  //{ziye 18} 方法表达式
}

接口简介

接口就是一种规范与标准,只是规定了要做哪些事情。具体怎么做,接口是不管的。

接口把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实

现了这个接口。

接口定义

type 接口名字 interface {

方法声明

}

接口的声明

可以为结构体添加接口中的方法,完成接口中方法实现

go 复制代码
package main

import "fmt"

// Personer 接口的声明
type Personer interface {
	SayHello() //方法声明
}

type Student struct {
}

// SayHello 使用student完成SayHello
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() //学生好

}

多态的定义与实现

什么是多态

所谓多态:指的是多种表现形式。

多态就是同一个接口,使用不同的实例而执行不同操作

go 复制代码
package main

import "fmt"

type Personer interface {
	SayHello()
}

type Student struct {
}

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

type Teacher struct {
}

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

//实现多态
func WhoSayHi(personer Personer) {
	personer.SayHello()
}

func main() {

	var stu Student
	var teacher Teacher
	WhoSayHi(&stu)
	WhoSayHi(&teacher)
}

案例

用多态来模拟实现 将移动硬盘或者U盘插到电脑上进行读写数据

go 复制代码
package main

import "fmt"

type Stroager interface {
	Read()
	Writer()
}

// MDisk 移动硬盘
type MDisk struct {
}

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

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

// UDisk U盘
type UDisk struct {
}

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

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

// Computer 定义一个函数
func Computer(s Stroager) {
	s.Writer()
	s.Read()
}
func main() {
	var uds UDisk
	var mds MDisk
	Computer(&uds)
	Computer(&mds)
}

案例

使用面向对象方式,实现一个计算器程序

案例实现一

go 复制代码
package main

import "fmt"

type Object1 struct {
}

func (o *Object1) GetResult(num1, num2 int, op string) int {
	//添加参数
	var result int
	switch op {
	case "+":
		result = num1 + num2
	case "-":
		result = num1 - num2
	}
	return result
}

func main() {
	var obj Object1
	result := obj.GetResult(8, 6, "+")
	fmt.Println(result)
}

案例实现二

go 复制代码
package main

import "fmt"

// 加法类
type Add struct {
	Object1
}

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

type Sub struct {
	Object1
}

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

type Object1 struct {
	numA int
	numB int
}

type Resulter interface {
	GetResult() int //返回类型int
}

func main() {
	add := Add{Object1{10, 8}}
	result := add.GetResult()
	fmt.Println(result)

	sub := Sub{Object1{10, 8}}
	result = sub.GetResult()
	fmt.Println(result)
}

案例实现三

go 复制代码
package main

import "fmt"

// 加法类
type Add struct {
	Object1
}

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

type Sub struct {
	Object1
}

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

type Object1 struct {
	numA int
	numB int
}

type Resulter interface {
	GetResult() int //返回类型int
}

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

// CreaeteOperator 创建一个方法,在该方法中完成对象的创建----封装
func (o *OperatorFactory) CreaeteOperator(op string, numA, numB int) int {
	switch op {
	case "+":
		add := Add{Object1{numA, numB}}
		return OperatorWho(&add)
	case "-":
		sub := Sub{Object1{numA, numB}}
		return OperatorWho(&sub)
	default:
		return 0
	}
}
// 多态
func OperatorWho(h Resulter) int {
	result := h.GetResult()
	return result
}
func main() {
	var operator OperatorFactory
	creaeteOperator := operator.CreaeteOperator("+", 20, 10)
	fmt.Println(creaeteOperator)
}

接口的继承与转换

go 复制代码
package main

import "fmt"

type Humaner interface {
	SayHello()
}

// Personer 接口继承
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()
	//超集可以转换为子集,反过来不可以
	//per = h
}

空接口定义与使用

go 复制代码
var i interface{} //空接口
i = 123
fmt.Println(i)

空接口可以赋任意的类型,切片s可以赋值各种类型的

go 复制代码
var s []interface{} //空接口切片s
	s = append(s, 123, "abc", 23.12)
	for i := 0; i < len(s); i++ {
		fmt.Println(s[i])
	}

空接口(interface{})不包含任何的方法,正因为如此,所有的类型都实现了空接口,因此空接口可以存储任意类型的数值

类型断言

通过类型断言,可以判断空接口中存储的数据类型。

语法:value, ok := m.(T)

m:表空接口类型变量

T:是断言的类型

value: 变量m中的值。

ok: 布尔类型变量,如果断言成功为true,否则为false

go 复制代码
package main

import "fmt"

func main() {
	var i interface{}
	i = 123
	value, ok := i.(int)

	if ok {
		fmt.Println(value)
	} else {
		fmt.Println("类型推断错误")
	}
}

案例--空接口与类型断言综合应用

计算器,完成数据校验

go 复制代码
package main

import "fmt"

// 加法类
type Add struct {
	Object1
}

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

func (add *Add) SetData(data ...interface{}) bool {
	//对数据的个数进行校验
	var b bool = true
	if len(data) > 2 || len(data) <= 1 {
		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
	}
	add.numA = value
	add.numB = value1
	//对传递过来的类型进行校验
	return b
}

type Sub struct {
	Object1
}

func (sub *Sub) GetResult() int {
	return sub.numA - sub.numB
}
func (sub *Sub) SetData(data ...interface{}) bool {
	//对数据的个数进行校验
	var b bool = true
	if len(data) > 2 || len(data) <= 1 {
		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
	}
	sub.numA = value
	sub.numB = value1
	//对传递过来的类型进行校验
	return b
}

type Object1 struct {
	numA int
	numB int
}

type Resulter interface {
	GetResult() int                   //返回类型int
	SetData(data ...interface{}) bool //完成参数运算的数据的类型校验
}

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

// CreaeteOperator 创建一个方法,在该方法中完成对象的创建----封装
func (o *OperatorFactory) CreaeteOperator(op string) Resulter {
	switch op {
	case "+":
		add := new(Add) //返回*add
		return add
	case "-":
		sub := new(Sub) //创建Sub 开辟相应的存储空间
		return sub
	default:
		return nil
	}
}

// 多态
func OperatorWho(h Resulter) int {
	result := h.GetResult()
	return result
}
func main() {
	var operator OperatorFactory
	creaeteOperator := operator.CreaeteOperator("-") //拿到对象
	setData := creaeteOperator.SetData(30, 10)
	if setData {
		who := OperatorWho(creaeteOperator)
		fmt.Println(who)
	}

}
相关推荐
CT随4 分钟前
Redis内存碎片详解
java·开发语言
anlog13 分钟前
C#在自定义事件里传递数据
开发语言·c#·自定义事件
奶香臭豆腐26 分钟前
C++ —— 模板类具体化
开发语言·c++·学习
晚夜微雨问海棠呀34 分钟前
长沙景区数据分析项目实现
开发语言·python·信息可视化
graceyun35 分钟前
C语言初阶习题【9】数9的个数
c语言·开发语言
小蜗牛慢慢爬行1 小时前
如何在 Spring Boot 微服务中设置和管理多个数据库
java·数据库·spring boot·后端·微服务·架构·hibernate
波音彬要多做1 小时前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
Swift社区1 小时前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
一道微光1 小时前
Mac的M2芯片运行lightgbm报错,其他python包可用,x86_x64架构运行
开发语言·python·macos
矛取矛求1 小时前
QT的前景与互联网岗位发展
开发语言·qt