Go 语言有着自己对面向对象的理解,它也有着自己的封装、继承、多态。
go 语言面向对象编程的特点为:
- 类与对象:Go 没有类,但是有类型
type struct {}
- 封装(数据隐藏):和别的 OO 语言有 4 个或更多的访问层次相比,Go 把它简化为了 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 作为参数传递同样可以正常运行。
结论:实体类型以值接收者实现接口的时候,不管是实体类型的值,还是实体类型值的指针,都实现了该接口。