GO语言的面向对象,有点不一样
GO语言从诞生发布到如今已经有10年了。这些年如日中天的区块链,AI等行业都少不了GO语言。
相比较Java,C#,C++这些面向对象的高级语言来讲,Go语言一切都是为了简单设计而设计的。
接下来从面向对象入手,一起探究GO语言的不同。
1、封装
封装的字面意思可以理解为把多种个体封成一个整体。
结构体类型是一种抽象数据类型,在其他高级语言中多用类的概念来实现。
由于Go语言没有类的概念,所以结构体struct在Go语言的数据抽象与封装占有非常重要的地位。
我们很容易通过构造工厂模式实现类似的构造方法。下面我们通过一段代码示例来看下对象实例化方法:
type Car struct {
Color string
Number int}func NewCar(color string,num int) *Car{ if num > 0{ return nil
} return &Car{color,num}
}
示例化的时候通过一下方式:
car1 := &Car{"Red",123}
car2 := NewCar("Green",456)
fmt.Printf("Car1=%v\n",car1)
fmt.Printf("Car2=%v\n",car2)
我们可以看出通过对象的直接赋值,Go语言中往往通过大写New开头的实例化方法来做工厂化的构造方法。
上述代码运行结果如下:
另外,封装包含两类内容:属性与方法。
type Car struct {
Color string
Number int}
func (car *Car) setNum(num int){
car.Number = num
}func NewCar(color string,num int) *Car{ if num < 0{ return nil
} return &Car{color,num}
}func main(){
car2 := NewCar("Green",456)
fmt.Printf("Num=%d\n",car2.Number)
car2.setNum(789)
fmt.Printf("Num=%d\n",car2.Number)
}
可以看出,我们通过方法名setNum前加(car *Car)的方式来定义一个属于Car类型的方法,此方法可以为任意Car对象调用。
以上代码运行输出:
2、继承
在面向对象的高级语言中往往通过子类继承父类的方式,有的是一对多有的是多对一。
一个父类多个子类(Java),一个子类集成多个父类(C++),子类可以继承父类的属性和方法。
Go语言不存在类这一概念,那么我们直接通过代码来看下Go中的继承。
type Object struct{
Width float64
length float64
weight float64
}
首先打算对Car这个结构体进行继承,其父结构暂时定义为Object物体,物体的基本属性有长度宽度以及重量。如上,我们定义父结构体。
对父结构体Object 定义类方法setWeight()如下:
func (object *Object) setWeight(weight float64){
object.weight = weight
}
使得能够通过set方法对Object对象示例进行重量属性的修改。
那么我们Car结构体如下继承呢,需要在Car结构体中定义一个匿名父结构体,代码如下:
type Car struct {
Object
Color string
Number int}
其中Object为Car的父结构体(其他语言叫基类、父类等),任何Car类型的示例都可以调用父类型Object的方法。我们可以通过如下完整代码进行验证:
type Object struct{
Width float64
length float64
weight float64
}
func (object *Object) setWeight(weight float64){ object.weight = weight
}
type Car struct {
Object
Color string
Number int}
func (car *Car) setNum(num int){
car.Number = num
}func NewCar(obj Object,color string,num int) *Car{ if num < 0{ return nil
} return &Car{obj,color,num}
}func main(){
car2 := NewCar(Object{2.0,3.2,1400},"Green",456)
fmt.Printf("car2=%v\n",car2)
car2.setWeight(345)
fmt.Printf("car2=%v\n",car2)
}
以上代码运行结果如下:
由此可知car具有了Object对象的属性,同时可以调用setWeight方法进行父结构体属性的修改,此为继承。
类似Car以匿名Object为父结构体,这样的匿名成员可以有多个,大家可以自己探索。
Go语言保留了接口interface的概念,可以通过interface进行多种实现(但是interface是一组方法的抽象并不包含属性)。
3、多态
Go语言通过接口来实现多态。
接口定义了一组方法,是一个方法集,这些方法集用以说明对象的行为。这些方法在接口中只包含定义不能有实现。并且接口只包含方法不能有成员变量。
只要Go语言中的类型实现了接口中的方法,此类型即实现了此接口,所以一个类型可以实现多个接口。下面我们通过一个例子来了解接口。
package mainimport "fmt"type Action interface {
forward()
}
type Monkey struct {
name string}
type Bear struct {
name string}
func (monkey *Monkey) forward(){
fmt.Printf("%s is moving forward\n",monkey.name)
}
func (bear *Bear) forward(){
fmt.Printf("%s is moving forward\n",bear.name)
}func main(){
monkey := &Monkey{"Monkey"}
bear := &Bear{"Bear"}
actions := []Action{monkey,bear} for _,obj := range actions{
obj.forward()
}
}
上述代码运行结果如下:
从代码中我们可以看到结构体Monkey与Bear都实现了Action接口,所以变量monkey与bear可以作为actions数组的元素。
每一个实现了Action接口的类型都意味着实现了forward()方法所以actions数组可以遍历元素依次调用其forward()的方法,可以发现每个具体类型的Action接口方法实现都不一样。
在实战中学习
学习GO语言归根到底一句话“在实践中学习,不能为了学习GO语言而学习”,要不断的去用,去解决问题,才能提高。