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语言而学习”,要不断的去用,去解决问题,才能提高。

posted @ 2020-11-09 18:46  51CTO学院  阅读(86)  评论(0编辑  收藏  举报