go

Go 系列 面向对象编程

Posted by lichao modified on July 10, 2020

Go 语言有着自己对面向对象的理解,它也有着自己的封装、继承、多态。

go 语言面向对象编程的特点为:

  • 类与对象:Go 没有类,但是有类型 type struct {}
  • 封装(数据隐藏):和别的 OO 语言有 4 个或更多的访问层次相比,Go 把它简化为了 2 层:
    1. 包范围内的:通过标识符首字母小写,对象 只在它所在的包内可见
    2. 可导出的:通过标识符首字母大写,对象 对所在包以外也可见
  • 继承:用组合实现:内嵌一个(或多个)包含想要的行为(字段和方法)的类型;多重继承可以通过内嵌多个类型实现
  • 多态:用接口实现:某个类型的实例可以赋给它所实现的任意接口类型的变量。类型和接口是松耦合的,并且多重继承可以通过实现多个接口实现。Go 接口不是 Java 和 C# 接口的变体,而且接口间是不相关的,并且是大规模编程和可适应的演进型设计的关键。

继承

继承只能描述现实世界的一小部分,使用继承是不全面的;go的设计选择的是组合,这个和现实世界比较吻合的设计,表现力更强;

多态

实现细节分析

如果要实现一个接口,必须实现这个接口提供的所有方法,但是实现方法的时候,可以使用指针接收者实现,也可以使用值接收者实现,这两者是有区别的。

指针接受者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type animal interface {
 printInfo()
}

type cat int

//指针接收者实现animal接口
func (c *cat) printInfo(){
 fmt.Println("a cat")
}

//需要一个animal接口作为参数
func invoke(a animal){
 a.printInfo()
}

func main() {
 var c cat
 //值作为参数传递
 invoke(c)
}

这个例子中把实现接口的接收者改为指针,但是传递参数的时候,我们还是按值进行传递,点击运行程序,会出现以下异常提示:

1
2
./main.go:10: cannot use c (type cat) as type animal in argument to invoke:
 cat does not implement animal (printInfo method has pointer receiver)

提示中已经很明显的告诉我们,说 cat 没有实现 animal 接口,因为 printInfo 方法有一个指针接收者,所以cat类型的值c不能作为接口类型animal传参使用。下面我们再稍微修改下,改为以指针作为参数传递。

1
2
3
4
5
func main() {
 var c cat
 //指针作为参数传递
 invoke(&c)
}

其他都不变,只是把以前使用值的参数,改为使用指针作为参数,我们再运行程序,就可以正常运行了。由此可见实体类型以指针接收者实现接口的时候,只有指向这个类型的指针才被认为实现了该接口。

值接受者:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type animal interface {
 printInfo()
}

type cat int

//值接收者实现animal接口
func (c cat) printInfo(){
 fmt.Println("a cat")
}

//需要一个animal接口作为参数
func invoke(a animal){
 a.printInfo()
}
1
2
3
4
5
6
7
8
9
10
11
func main() {
 var c cat
 //值作为参数传递
 invoke(c)
}

func main() {
 var c cat
 //指针作为参数传递
 invoke(&c)
}

增加一个 invoke 函数,该函数接收一个 animal 接口类型的参数,例子中传递参数的时候,也是以类型 cat 的值 c 传递的,运行程序可以正常执行。使用类型 cat 的指针 &c 作为参数传递同样可以正常运行。

结论:实体类型以值接收者实现接口的时候,不管是实体类型的值,还是实体类型值的指针,都实现了该接口。