✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑
文章目录
- Go语言怎样实现面向对象
- 1. 面向对象的三大特性
- (1)封装
- (2)继承
- Go语言的继承:结构体的嵌套
- 匿名字段方式继承
- 聚合方式叫组合,不再是继承了
- (3)多态
- 2. 方法
- (1)Go语言中的方法
- (2)方法与函数对比总结
- (3)方法的重写
Go语言怎样实现面向对象
Go语言(Golang)虽然不是一个纯粹的面向对象编程语言,但它通过结构体(Struct)、接口(Interface)等机制,提供了面向对象的编程范式。
在实际的项目开发中,使用面向对象的理念可以显著提高代码的可维护性、可扩展性和可复用性。
1. 面向对象的三大特性
面向对象编程(OOP)的核心思想是将数据和操作数据的行为封装到对象中,通过对象之间的交互来完成程序的功能。OOP具有三大特性:封装、继承、多态。
(1)封装
封装是指将某事物的属性和行为包装到对象中,这个对象只对外公布需要公开的属性和行为,而这个公布也是可以有选择性的。在Go语言中,封装主要通过结构体实现。
(2)继承
生活中的继承:
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是:is-a,父类更通用,子类更具体。
虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。
继承就是子类继承父类的特征和行为,使得子类具有父类的属性和方法,使得子类具有父类相同的行为。子类会具有父类的一般特性也会具有自身的特性。
java语言的继承,显示声明class User extends Person{
name
age
}
如此,当修改父类名称或者其中的方法,属性名称后,所有的子类的都得同步去改,比较麻烦
Go语言的继承:结构体的嵌套
Go语言中结构体嵌套,有两种方式
1、模拟继承 is - a
哪个结构体被继承(父类),就将哪个结构体当做一个字段写到 子类结构体里面
type A struct{
field
}
type B struct{
A // 匿名字段 B.A
field
}
// B继承A,B是可以直接访问A的属性的
2、聚合关系 has - a
type C struct{
field
}
type D struct{
c C //聚合关系,不使用匿名字段
field
}
// D是无法直接访问C中的属性的,必须使用D.c.c_field
匿名字段方式继承
package main
import "fmt"
// Person 定义一个父类
type Person struct {
name string
age int
}
// Student 定义一个子类,Student拥有了父类所有的属性,还有自己的特性
type Student struct {
Person // 父类以匿名字段形式作为子类的属性,实现了继承。
school string
}
func main() {
// 1、 创建父类对象
p1 := Person{name: "jingtian", age: 18}
fmt.Println(p1)
fmt.Println(p1.name, p1.age)
// 2、创建子类
s1 := Student{Person: Person{name: "小明", age: 3}, school: "景天科技苑"}
fmt.Println(s1)
fmt.Println(s1.Person.name, s1.Person.age, s1.school)
// 3、创建子类
var s2 Student
s2.Person.name = "张三"
s2.Person.age = 3
s2.school = "北大"
fmt.Println(s2)
// 概念:提升字段, 只有匿名字段才可以做到
// Person 在Student中是一个匿名字段, Person中的属性 name age 就是提升字段
// 所有的提升字段就可以直接使用了,不需要再通过匿名字段点来获取了
var s3 Student
//字段提升,可以直接用子类对象操作父类字段
s3.name = "李四"
s3.age = 4
s3.school = "清华"
fmt.Println(s3)
fmt.Println(s3.name, s3.age)
}
聚合方式叫组合,不再是继承了
package main
import "fmt"
//聚合继承
type Human struct {
name string
age int
}
type Man struct {
//聚合继承,不再以匿名字段形式将父类写在这,而是命名一个变量名
Human Human
phone string
}
func main() {
//创建子类对象
man := Man{
Human: Human{"轩辕氏", 999},
phone: "19899999999",
}
fmt.Println(man)
//访问父类属性,聚合继承不能使用变量提升。提升字段, 只有匿名字段才可以做到
//聚合方式继承,访问父类属性需要写全,对象.变量名.父类字段名
fmt.Println(man.Human.name)
}
继承就是子类继承父类的特征和行为,使得子类具有父类的属性和方法,使得子类具有父类相同的行为。子类会具有父类的一般特性也会具有自身的特性。
匿名字段 + 提升字段:Go语言中的匿名字段。
当继承多个父类具有相同属性字段的时候,就不能再使用字段提升了,因为此时就不能确定使用的是哪个父类的属性。
此时就要加上父类.属性名
(3)多态
多态需要结合接口实现,由于篇幅限制,下一章接着更新,敬请期待!
2. 方法
(1)Go语言中的方法
Go语言中同时拥有函数和方法。一定要和其他只有方法的语言区分开
类:结构体->属性、方法?
Go语言实现方法
方法:需要指定调用者,约定这个方法属于谁的. 对象.方法()
函数:不需要指定调用者,定义了函数就可以直接函数名()调用
方法:可以理解为函数多了一个调用者
方法定义, func 方法调用者 方法名(){} 方法的定义比函数多了个调用者
定义中,函数与方法就不一样,函数是 func 函数名(参数) 返回值 返回值类型 {}
1、方法可以重名,只需要调用者不同
2、如果调用者相同,则不能重名
package main
import "fmt"
// 方法:可以理解为函数多了一个调用者
// 方法可以重名,不同的对象,调用的结果是不一样的
type Dog struct {
name string
age int
}
// 方法定义, func 方法调用者 方法名()
// 1、方法可以重名,只需要调用者不同
// 2、如果调用者相同,则不能重名
func (dog Dog) eat() {
fmt.Println("Dog eating...")
}
func (dog Dog) sleep() {
fmt.Println("Dog sleep...")
}
// 在Go语言中,fmt.Sprintf函数是一个非常实用的函数,它可以将一个字符串格式化为指定的格式。
// 它的用途非常广泛,可以用来构建复杂的字符串,包括打印日志、生成报错信息等。
// 带有参数和返回值的方法
func (dog Dog) xiaohua(food string) string {
//返回值字符串格式化
return fmt.Sprintf("%v吃进了%s, 吐出来骨头", dog.name, food)
}
type Cat struct {
name string
age int
}
func (cat Cat) eat() {
fmt.Println("Cat eating...")
}
func (cat Cat) sleep() {
fmt.Println("Cat sleep...")
}
func main() {
// 创建一个对象
dog := Dog{
name: "旺财",
age: 2,
}
fmt.Println(dog)
// 方法的调用,通过对应的结构体对象来调用
dog.eat()
//调用带有参数和返回值的方法
back := dog.xiaohua("肉")
fmt.Println(back)
//不同对象调用同名方法
cat := Cat{name: "喵喵", age: 1}
cat.eat()
//打印查看方法所属类型,类型跟函数一样都是func()
fmt.Printf("方法所属类型: %T\n", cat.eat)
}
(2)方法与函数对比总结
方法:
- 某个类的行为功能,需要指定调用者
- 一段独立的代码功能,必须要使用调用者来调用
- 多个类的方法可以重名,单个类不行
- 方法是某个类的动作
函数:
-
一段独立的代码功能,可以直接调用
-
命名完全不能冲突
-
函数是一个特殊的类型
(3)方法的重写
需要和继承结合
子类可以重写父类的方法 override
子类还可以新增自己的方法
子类可以访问父类中的属性和方法
子类重写父类方法,方法名与父类方法相同,只是调用者改成了子类
package main
import (
"fmt"
)
// 方法重写,建立在父类和子类结构上的
type Animal struct {
name string
age int
}
// 父类方法
func (animal Animal) eat() {
fmt.Println(animal.name, " 正在吃....")
}
func (animal Animal) sleep() {
fmt.Println(animal.name, " 正在sleep....")
}
//父类更通用,子类更具体
// 子类
type Dog2 struct {
Animal
}
// 子类自己的方法
func (dog Dog2) wang() {
fmt.Println("wangwangwanwg~~~")
}
type Cat2 struct {
Animal
color string // 子类可以定义自己的属性
}
// 子类重写父类的方法 , 子类的方法名和父类同名,即可重写父类的方法
func (cat Cat2) eat() {
fmt.Println(cat.name, " 正在吃cat....")
}
func main() {
// 定义一个子类,使用父类方法
dog := Dog2{Animal{name: "旺财", age: 3}}
dog.eat() // 调用父类的方法
dog.wang() // 调用自己扩展的方法
cat := Cat2{Animal{name: "煤球", age: 3}, "黑色"}
cat.eat() // 如果重写了父类的方法就是调用子类自己的方法
fmt.Println(cat.color) // 调用子类自己的属性
// 子类可以操作父类的方法,父类可以操作子类的吗?不可以
// 父类不能调用子类自己的扩展的方法
a := Animal{name: "大黄", age: 3}
//父类调用与子类同名方法,只能调用到父类自己的方法,不能调用子类扩展后的方法
a.eat()
a.sleep()
}
Go语言面向对象详细教程,更高级的应用,持续更新中,感兴趣的朋友可以关注下,ღ( ´・ᴗ・` )比心