之前介绍的结构体组合实际上是实现不了多态的,为了实现多态需要引入interface概念。

通过interface实现多态

  • interface定义一系列抽象的方法,子类去实现这些interface,从而达成一个多态的形式。
  • interface本质是一个指针,内部构造有一个指针指向的是当前interface指向的具体类型,还有一个指针指向的是当前的这个类型所包含的函数列表。

    下面使用interface来实现多态:

    package main
    
    import "fmt"
    
    // 声明接口,本质上是一个指针
    type AnimalIF interface {
      Sleep()
      GetColor() string // 获取动物的颜色
      GetType() string // 获取动物的种类
    }
    
    // 具体的类,类继承接口不需要像继承父类那样将接口名写入struct内,只需要在类中实现接口中声明的方法即可
    type Cat struct {
      color string //猫的颜色
    }
    
    // 注意:具体的类必须要实现接口中声明的所有方法才会算是继承这个接口,只实现接口中部分方法会导致接口的指针无法指向具体的类
    // 实现接口中声明的Sleep方法
    func (this *Cat) Sleep() {
      fmt.Println("Cat is Sleep")
    }
    
    // 实现接口中声明的GetColor方法
    func (this *Cat) GetColor() string {
      return this.color
    }
    
    // 实现接口中声明的GetType方法
    func (this *Cat) GetType() string {
      return "Cat"
    }
    
    // 具体的类2
    type Dog struct {
      color string
    }
    
    func (this *Dog) Sleep() {
      fmt.Println("Dog is Sleep")
    }
    
    func (this *Dog) GetColor() string {
      return this.color
    }
    
    func (this *Dog) GetType() string {
      return "Dog"
    }
    
    
    func main() {
      var animal AnimalIF // 定义接口的数据类型,父类的指针
      animal = &Cat{"Green"} // 将接口指针指向具体的类的地址
      animal.Sleep() // 调用Cat类的Sleep()方法,多态的现象
    
      animal = &Dog{"Yellow"}
      animal.Sleep() // 调用Dog类的Sleep()方法,多态的现象
    }
    
  • 6-10行声明AnimalIF接口,并声明三个方法
  • 12-31行创建一个具体的Cat类

    • 重写实现AnimalIF接口定义的三个方法
  • 33-48行创建一个具体的Dog类
  • 第52行定义接口数据类型,相当于创建接口的指针
  • 第53行将接口的指针指向具体的类的地址
  • 第54行调用具体的类重写实现的方法,实现多态

运行结果:
image.png

体现多态的另一个例子

上面的例子可能不太好呈现多态的作用,现在额外顶一个函数,这个函数的参数是接口的数据类型,这样Cat类或者Dog类都可以作为参数传递进去,并且分别调用各自重写的方法。

package main

import "fmt"

// 声明接口,本质上是一个指针
type AnimalIF interface {
    Sleep()
    GetColor() string // 获取动物的颜色
    GetType() string // 获取动物的种类
}

// 具体的类,类继承接口不需要像继承父类那样将接口名写入struct内,只需要在类中实现接口中声明的方法即可
type Cat struct {
    color string //猫的颜色
}

// 注意:具体的类必须要实现接口中声明的所有方法才会算是继承这个接口,只实现接口中部分方法会导致接口的指针无法指向具体的类
// 实现接口中声明的Sleep方法
func (this *Cat) Sleep() {
    fmt.Println("Cat is Sleep")
}

// 实现接口中声明的GetColor方法
func (this *Cat) GetColor() string {
    return this.color
}

// 实现接口中声明的GetType方法
func (this *Cat) GetType() string {
    return "Cat"
}

// 具体的类2
type Dog struct {
    color string
}

func (this *Dog) Sleep() {
    fmt.Println("Dog is Sleep")
}

func (this *Dog) GetColor() string {
    return this.color
}

func (this *Dog) GetType() string {
    return "Dog"
}

func showAnimal(animal AnimalIF) { // 将接口作为参数传入
    animal.Sleep() // 多态
    fmt.Println("color = ",animal.GetColor())
    fmt.Println("kind = ",animal.GetType())
}

func main() {
    cat := Cat{"black"}
    dog := Dog{"yellow"}

    showAnimal(&cat)
    showAnimal(&dog)
}
  • 50-54行创建一个函数用来打印传入的类,函数用来打印传入的具体的类的属性和调用其重写的方法

运行结果:
image.png

多态的基本要素

  • 有父类(有接口,接口的方法没有被实现)

    • 声明接口,定义需要实现的方法
  • 有子类(这个子类实现了父类的全部接口方法)

    • 声明具体的子类,并且需要实现全部接口中定义的方法
  • 父类类型的变量(指针)指向(引用)子类的具体数据变量

    • 用父类的指针(接口)指向一个具体的实例化对象
    • 之后使用父类(即接口)中定义的方法,相当于调用子类(具体的类)中实现的方法,从而实现多态
最后修改:2024 年 03 月 13 日
如果觉得我的文章对你有用,请随意赞赏