参考资料
参考资料
Go
语言并没有设计诸如虚函数、纯虚函数、继承、多重继承等概念,但它通过接口却非常优雅地支持了面向对象的特性。
多态是一种运行期的行为,它有以下几个特点:
- 一种类型具有多种类型的能力
- 允许不同的对象对同一消息做出灵活的反应
- 以一种通用的方式对待个使用的对象
- 非动态语言必须通过继承和接口的方式来实现
看一个实现了多态的代码例子:
1package main
2
3import "fmt"
4
5func main() {
6 qcrao := Student{age: 18}
7 whatJob(&qcrao)
8
9 growUp(&qcrao)
10 fmt.Println(qcrao)
11
12 stefno := Programmer{age: 100}
13 whatJob(stefno)
14
15 growUp(stefno)
16 fmt.Println(stefno)
17}
18
19func whatJob(p Person) {
20 p.job()
21}
22
23func growUp(p Person) {
24 p.growUp()
25}
26
27type Person interface {
28 job()
29 growUp()
30}
31
32type Student struct {
33 age int
34}
35
36func (p Student) job() {
37 fmt.Println("I am a student.")
38 return
39}
40
41func (p *Student) growUp() {
42 p.age += 1
43 return
44}
45
46type Programmer struct {
47 age int
48}
49
50func (p Programmer) job() {
51 fmt.Println("I am a programmer.")
52 return
53}
54
55func (p Programmer) growUp() {
56 // 程序员老得太快 ^_^
57 p.age += 10
58 return
59}
代码里先定义了 1 个 Person
接口,包含两个函数:
1job()
2growUp()
然后,又定义了 2 个结构体,Student
和 Programmer
,同时,类型 *Student
、Programmer
实现了 Person
接口定义的两个函数。注意,*Student
类型实现了接口, Student
类型却没有。
之后,我又定义了函数参数是 Person
接口的两个函数:
1func whatJob(p Person)
2func growUp(p Person)
main
函数里先生成 Student
和 Programmer
的对象,再将它们分别传入到函数 whatJob
和 growUp
。函数中,直接调用接口函数,实际执行的时候是看最终传入的实体类型是什么,调用的是实体类型实现的函数。于是,不同对象针对同一消息就有多种表现,多态
就实现了。
更深入一点来说的话,在函数 whatJob()
或者 growUp()
内部,接口 person
绑定了实体类型 *Student
或者 Programmer
。根据前面分析的 iface
源码,这里会直接调用 fun
里保存的函数,类似于: s.tab->fun[0]
,而因为 fun
数组里保存的是实体类型实现的函数,所以当函数传入不同的实体类型时,调用的实际上是不同的函数实现,从而实现多态。
运行一下代码:
1I am a student.
2{19}
3I am a programmer.
4{100}
参考资料
【各种面向对象的名词】https://cyent.github.io/golang/other/oo/
【多态与鸭子类型】https://www.jb51.net/article/116025.htm