之前介绍的结构体组合实际上是实现不了多态的,为了实现多态需要引入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行调用具体的类重写实现的方法,实现多态
体现多态的另一个例子
上面的例子可能不太好呈现多态的作用,现在额外顶一个函数,这个函数的参数是接口的数据类型,这样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行创建一个函数用来打印传入的类,函数用来打印传入的具体的类的属性和调用其重写的方法
运行结果:
多态的基本要素
有父类(有接口,接口的方法没有被实现)
- 声明接口,定义需要实现的方法
有子类(这个子类实现了父类的全部接口方法)
- 声明具体的子类,并且需要实现全部接口中定义的方法
父类类型的变量(指针)指向(引用)子类的具体数据变量
- 用父类的指针(接口)指向一个具体的实例化对象
- 之后使用父类(即接口)中定义的方法,相当于调用子类(具体的类)中实现的方法,从而实现多态
此处评论已关闭