前言
本人之前是写Java的,众所周知Java是典型的面向对象编程语言,那go怎么实现面向对象编程呢?
本文就是来探索go如何进行面向对象编程!
面向对象三大特性
- 封装
- 继承
- 多态
组合
组合是go语言实现面向对象编程的关键。
实现封装
go语言可以通过定义结构体来封装对象的属性和行为,比如:
type Person struct {
Name string
Age int
}
func (person Person) eat() {
// ...
}
func (person Person) drink() {
// ...
}
func (person Person) sleep() {
// ...
}
func (person Person) work() {
// ...
}
func main() {
person := Person{"张三", 18}
person.eat()
person.drink()
person.sleep()
person.work()
}
实现继承
对象继承
go语言可以通过结构体嵌入实现对象的继承。
简单介绍下结构体嵌入和匿名成员(详见):
什么是匿名成员?
结构体的成员仅指定成员的数据类型而不指定成员的名称,这类成员就是匿名成员。匿名成员也有成员名称,就是类型名称,可以通过类型名称访问匿名成员。
什么是结构体嵌入?
结构体嵌入机制让一个结构体包含另一个结构体类型的匿名成员,这样就可以通过简单的点运算符x.f来访问匿名成员链中嵌套的x.d.e.f成员。总之,结构体嵌入机制方便访问嵌套结构体的成员和方法。
示例:
type Point struct {
X, Y int
}
func (p Point) getPoint() (int, int) {
return p.X, p.Y
}
type Circle struct {
Point
Radius float64
}
func (c Circle) getArea() float64 {
return math.Pi * c.Radius * c.Radius
}
func main() {
circle := Circle{Point{1, 2}, 3}
// 直接访问匿名结构体成员的属性
fmt.Println(circle.X, circle.Y)
// 直接访问匿名结构体成员的方法
x, y := circle.getPoint()
fmt.Println(x, y)
fmt.Println(circle.getArea())
}
可以看到,通过把Point
结构体嵌入Circle
结构体中,Circle
对象看起来也拥有了Point
对象的属性和方法。
接口继承
go语言可以通过接口内嵌实现接口的继承。
示例:
type I1 interface {
Method1() string
}
// I2接口嵌入了I1接口,则I2继承了I1接口
type I2 interface {
I1
Method2() string
}
type Test struct{}
func (t Test) Method1() string {
return "Method1"
}
func (t Test) Method2() string {
return "Method2"
}
func main() {
test := Test{}
// test既是I1接口实例
t1(test)
// test又是I2接口实例
t2(test)
}
// 需要I1接口实例
func t1(i1 I1) {
fmt.Println("t1...", i1.Method1())
}
// 需要I2接口实例
func t2(i2 I2) {
// 可以看到I2也有Method1方法
fmt.Println("t2...", i2.Method1())
fmt.Println("t2...", i2.Method2())
}
实现多态
示例:
type Animal interface {
// 物种
Type() string
}
type Cat interface {
Animal
// 猫的颜色
Color() string
}
type WhiteCat struct{}
func (wc WhiteCat) Type() string {
return "猫科动物"
}
func (wc WhiteCat) Color() string {
return "白色"
}
type BlackCat struct{}
func (bc BlackCat) Type() string {
return "猫科动物"
}
func (bc BlackCat) Color() string {
return "黑色"
}
func main() {
whiteCat := WhiteCat{}
blackCat := BlackCat{}
catColor(whiteCat) // cat color: 白色
catColor(blackCat) // cat color: 黑色
}
func catColor(cat Cat) {
fmt.Println("cat color:", cat.Color())
}
可以看到,不同的猫Color
方法的实现不同。
模拟构造函数
最佳实践:
通常会定义NewXXX
方法来创建一个结构体,NewXXX
方法通常会返回结构体指针,如下:
type Person struct {
}
func NewPerson() *Person {
return &Person{}
}
func main() {
person := NewPerson()
fmt.Printf("person:%v\n", person)
}