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

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。

猜你喜欢

转载自blog.csdn.net/weixin_43314519/article/details/119682870