面向对象编程有三大特点:继承,封装和多态
1.继承
Go并不提供语法层面的继承实现。对于接口,Go提供了“鸭子类型”的实现,不需要在定义结构体是明确指出实现了哪个接口,只要结构体有某个接口的全部方法,那么就算实现了该接口。对于结构体, 可以通过“内嵌”的方式让“子类”拥有“父类”的方法和字段(也仅仅是语法层面的拥有,实际上是一个隐式字段代替持有)。在下面的代码中,展示了什么是内嵌
type Person struct{
Name string
Age int
}
type Student struct{
Person //这里就表示内嵌,语法是仅写类型,不需要字段名
SchoolName string
}
func main(){
stu := Student{
Person: Person{Name: "Mike", Age: 12}, //明明Student中没有“Person”这个字段,这个“Person”哪儿来的??? 所谓“内嵌”本质是聚合,Go会生成一个隐式的字段,并且这个字段的名称就是类型的名称
SchoolName: "xx小学",
}
fmt.Println(stu.Person.Name) //输出“Mike”,从这里就能清楚的看到隐式字段“Person”
fmt.Println(stu.Name) //输出“Mike”,直接不写隐式字段,也能获得同样的结果
}
这种“内嵌”生成的“父子”关系不符合里氏替换原则。与其说这是一种继承,还不如说这仅仅是Go为了写代码方便提供的一种语法。“内嵌”这种写法除了能点出“父类”的字段和方法之外,其他没有任何地方像继承。
2.封装
几乎所有的现代高级语言都实现了一定程度上的封装。在Go中,可以使用结构体(自定义数据结构)来封装属性和方法,用package封装结构体、结构、变量,最终实现“高内聚,低耦合”
3.多态
Java中有override和overload两种实现多态的方法,可惜Go语言都不支持。首先,overload肯定是不支持的,Go不允许有同样方法名的方法出现在同一个结构体中。不要跟Go说方法的签名应该包括方法名,方法参数,Go只认方法名。 其次,override也不支持。因为Go的内嵌“继承”方式不符合里氏替换原则,那就不可能真正实现override。唯一与override相似的地方就是可以在“子类”中定义一个与“父类”中同名的方法。
由此可以得出:Go并不是完全支持面向对象编程。甚至可以这么说,Go的语法仅仅能使程序看起来是面向对象,但实际上不是。