Notes
Go
面向对象

面向对象编程

面向对象编程将对象作为编程语言的核心,这意味着在构建和设计整个项目的时候,首先考虑的是行动的主体——对象,再去给对象附加应该具备的字段和行为。

封装、继承、多态是面向对象编程的三大特性。Go 语言也同样对这三大特性进行了支持。但是再 Go 语言中我们可以采用面向对象和面向过程的混合编程方式。

封装

封装是将属于某个对象的字段和行为抽象出来,形成一个有机体,可以使用权限机制来保护字段和方法,使其不能被其他的代码直接访问。

Go 语言中通过大小写来控制字段和方法的访问权限,大写字母开头的字段和方法是公开的,小写字母开头的字段和方法是私有的。

我们可以使用 struct 来定义一个对象:

type Worker struct {
    Name string
    Age int
    Position string
}

成员函数可以通过 func 关键字定义:

func (w Worker) Work() {
    fmt.Printf("%s is working\n", w.Name)
}

函数名前面的 w Worker 是接收者,表示函数 WorkWorker 类型的方法。调用方法的时候,可以通过 . 运算符来调用:

w := Worker{Name: "Alice", Age: 20, Position: "Engineer"}
 
w.Work()

要注意的是,上面我们定义的 Work 方法是值接收者,在这种情况下,Work 方法对 w 的修改不会影响到原始对象。

func (w Worker) Work() {
    fmt.Printf("%s is working\n", w.Name)
    w.Name = "Bob"
}
 
w.Work()
 
fmt.Println(w.Name) // Alice

运行结果:

Alice is working
Alice

可见,Work 方法对 w 的修改不会影响到原始对象。

如果我们想要修改原始对象,可以使用指针接收者:

func (w *Worker) Work() {
    fmt.Printf("%s is working\n", w.Name)
    w.Name = "Bob"
}
 
w.Work()
 
fmt.Println(w.Name) // Bob

运行结果:

Alice is working
Bob

继承

Go 语言不提供类似 extends 的关键字来实现继承,我们可以使用组合的方式来实现继承。

type Person struct {
    Name string
    Age int
}
 
func (p Person) Say() {
    fmt.Printf("%s is saying\n", p.Name)
}
 
type Worker struct {
    Person
    Position string
}
 
func (w Worker) Work() {
    fmt.Printf("%s is working\n", w.Name)
}

Worker 类型嵌套了 Person 类型,这样 Worker 就拥有了 Person 的字段和方法。

w := Worker{Person: Person{Name: "Alice", Age: 20}, Position: "Engineer"}
 
w.Say()
 
w.Work()

运行结果:

Alice is saying
 
Alice is working

将字段进行匿名化:

type Worker struct {
    Person
    Position string
}

声明时:

h := Person{Name: "Alice", Age: 20}
w := Worker{
  h,
}