Go语言里如何采用面向对象编程?Go中一样能够面向对象!

Go语言虽无class,但可通过embed type实现类似继承的效果,以及利用类型组合实现行为的多样组合。文中详细阐述了如何通过embed type实现继承,并通过interface的组合展现Go中的面向对象特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Go 里也有面向对象

Go语言虽然没有class,不过Go也是可以实现Object Oriented的。接下来让我们尝试在Go中使用面向对象,看看能否找到最佳实践。

使用 embed type 实现继承

Go 中的嵌入类型 embed type 本质上是一种 composition,Go 不像其它 OO 语言那样提供基于类的继承,那些继承体现的是 is-a 关系,但是 Go 不是。

Go 通过 embed type,可以实现 method 和 field 的复用。

package main

import (
    "fmt"
)

type Person struct {
    name string
    age  int
}

func (p *Person) sayName() {
    fmt.Println(p.name)
}

type Student struct {
    Person
    name string
}

func main() {
    p := Person{name: "C"}
    p.sayName() // #1 C

    s1 := Student{name: "Java"}
    s1.sayName() // #2 此行输出空字符串

    s2 := Student{name: "Java", Person: Person{name: "VB"}}
    s2.sayName()         // #3 VB
    fmt.Println(s2.name) // #4 Java
    fmt.Println(s2.Person.name) //#5 VB
}

PersonStudent 的 embed type,因而 Student 可以直接使用 Person 的 field 和 method,需要注意的是:

1.Student 中的同名属性可以遮蔽 embed type 的属性,#4 的输出
2.Student 虽然可以直接调用 embed type 的 method,但是 method 的 receiver 仍然是 embed type,所以 #2 输出为空。
3.直接通过 embed type 继承,embed type 无法获取被嵌入类型的属性,原因由 2 导致。

类型组合的强大魔力

Go 支持任意类型的 embed type,当然也包括 interface type,通过组合就可以实现多种不同行为的任意组合,这也是 Go 倡导以更小的单元实现你的代码功能,然后组合它们的理念。

// student 行为
type StudentTalk interface {
    talk()
}

// teacher 行为
type TeacherTalk interface {
    say()
}

首先定义两个 interface 用来表示不同的行为。

// people 行为
type PeopleTalk interface {
    StudentTalk
    TeacherTalk
}

通过 embed type 把定义的两个 interface 组合为新的 interface PeopleTalk,此时 PeopleTalk 继承了两个 interface 的 method 集合,也就是 PeopleTalk 拥有了 StudentTalk 和 TeacherTalk 的 method 合集。

type Person struct {
    TeacherTalk
    StudentTalk
}

Person 也内嵌了 TeacherTalk 和 StudentTalk,对 Person 来说既可以理解成继承了两个 interface 的 method 集合,也可以理解是 Person 拥有两个类型为 TeacherTalk 和 StudentTalk 的 field,它们的分别可以被赋值为实现了它们的 struct 的值。

type Student struct{}

func (s *Student) talk() {
    fmt.Println("student talk")
}

type Teacher struct{}

func (t *Teacher) say() {
    fmt.Println("teacher say")
}

Struct Student 和 Teacher 分别实现了 StudentTalk 和 TeacherTalk。

func meet(p PeopleTalk) {
    fmt.Println("====>people meet<====")
    meetTeacher(p)
    meetStudent(p)
}

func meetTeacher(ps TeacherTalk) {
    fmt.Println("====>teacher meet<====")
    ps.say()
}

func meetStudent(ps StudentTalk) {
    fmt.Println("====>student meet<====")
    ps.talk()
}

func main() {
    t := Teacher{}
    s := Student{}
    // Person 实现了 PeopleTalk 方法,通过 Teacher 和 Student 实例
    p := Person{TeacherTalk: &t, StudentTalk: &s}
    meet(p)
}

上面这段 Go 代码展示了 interface 组合带来的魔力,meet function 的参数是 PeopleTalk,而 Person 的实例 p 由于通过实例 t 和 s 实现了 PeopleTalk 的 method,也就是说 p 可以直接通过 meet 函数传递,meet 的参数 PeopleTalk,而且实现了 PeopleTalk 必然实现了 StudentTalk 和 TeacherTalk,因为 PeopleTalk 是由它们组合而成的,进而可以在 meet 函数中可以直接调用 meetTeacher 和 meetStudent,它们各自的参数分别是 TeacherTalk 和 StudentTalk。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值