说到面向对象,总想到的是C++,最近看go,感觉其接口设计用起来也是蛮爽的;
go的接口只需要对应的结构体实现了相应接口的方法(一样参数,一样返回值),那么go就可以实现类似C++的运行时多态:可以将一个实现了该接口的结构体实例传入函数参数中,实现多态效果,但是go的语法没有C++限制那么严格,不需要通过冒号去写继承的代码,只需要实现接口那些函数就认为实现那个接口了。
很好理解,既然都实现了那些接口的函数,那就可以认为实现了那个接口,简单直接,省去了C++的继承代码,虽然可能会稍微导致代码不可读性,但是只要有好的命名习惯,就还是很容易可以知道某个结构的函数是个对象的。
我们知道go的interface可以等于任何值,这为多态实现提供便利;
我们使用一个例子来考虑用go怎么写:
首先假设动物有吃东西这个接口,用go描述:
···
type Animal interface {
Eat(food interface{})
}
···
我们将Eat的参数使用interface,表示可以接收任何类型的参数(虽然这样也不太对,应该是食物才对,暂且这么写吧)
然后,我们考虑人和猴子两个对象,都属于动物,那他们都应该实现Animal的接口吧,同时我们给他们加上一些属性,如体重,名称吃喝拉撒什么的都要有,用go描述:
type Human struct {
Weight int
Name string
}
type Monkey struct {
Weight int
Kind string
}
然后对应的接口实现描述:
func (this *Human) Eat(food interface{}) {
fmt.Println("human "+ this->Name + " eat a " + food.(string))
}
func (this *Monkey) Eat(food interface{}) {
fmt.Println("monkey eat a " + food.(string))
}
写个main函数试试
package main
import (
"fmt"
)
func main() {
human := &Human{Weight:100,Name:"hijiang"}
monkey := &Human{Weight:60, Kind:"金丝猴"}
human.Eat("apple")
monkey.Eat("bannaner")
}
最后输出:
- human hijiang eat a apple
- monkey eat a bannaner
如果再进一步考虑,食物还不应该是随便一种类型,需要有限制,那么用go描述一个食物:
type Food interface {
GetWeight() int
GetName() string
}
//我们特意将其成员变量小写,然后实现个接口,分别获取食物的重量和名称
接下来我们实现一个具体的食物apple和bannaner吧:
type Apple struct {
weight int
name string
}
type Bannaner struct {
weight int
name string
}
func (this *Apple ) GetWeight() int {
return this.weight
}
func (this *Apple ) GetName() string {
return this.name
}
func (this *Bannaner) GetWeight() int {
return this.weight
}
func (this *Bannaner) GetName() string {
return this.name
}
接下来我们限制下Animal接口只能输入Food类型(其实,Food是接口类型的话,可以接受任何类型):
type Animal interface {
Eat(food Food)
}
然后修改下Human和Monkey的接口:
func (this *Human) Eat(food Food) {
fmt.Println("human "+ this->Name + " eat a " + food.GetName()+",weight="+food.Weight())
}
func (this *Monkey) Eat(food Food) {
fmt.Println("monkey eat a " + food.GetName()+",weight="+food.Weight())
}
main:
func main() {
human := &Human{Weight:100,Name:"hijiang"}
monkey := &Human{Weight:60, Kind:"金丝猴"}
apple := &Apple{weight:100,name:"苹果"}
bannaner := &Bannaner{weight:200, name:"香蕉"}
human.Eat(apple)
monkey.Eat(bannaner)
}
代码编写过程发现,函数名称一样接收器不一样是会被视为重复定义的,这个暂时还没搞明白为什么要这样。
关于go的结构体类貌似是不能用来做类似这种多态编程,暂时不研究。