理解Go中的接口和多态

Go中的多态

go中的多态是通过接口实现的,在了解接口之前先引出方法这一概念。
在go中,方法区别于函数:函数通常指为了实现某些目的,打包的一系列有明确逻辑关系的语句;而方法则是一个需要绑定特殊类型的函数。这种“拼接”的方式,让方法有了类似其他面向对象语言中类方法的作用,即某种功能和目的的实现依赖于实例化后的对象。



有如下参考代码:

package main

import (
    "fmt"
)

type Person struct {
    Name string
    Age  int
}

func (P Person) Eat() {
    fmt.Println(P.Name, "可以吃肉和菜")
}

func main() {
    person := Person{Name: "李华"}
    person.Eat() // 李华 可以吃肉和菜
}

可以看到方法的使用:在实例化一个Person对象之后,通过“对象.方法名”的形式,让“李华”这一对象执行了“Eat”方法,和C++、Python等语言中的类操作具有高度的相似性,go通过“方法”的这种形式,让自己拥有了面向对象的基础。
接下来讨论go中的多态。
假设,在实际场景中,除了Person类可以做出Eat的动作,Dog类和Cat类也可以做出Eat的动作,我们需要他们分别做出Eat的动作,来记录他们吃的东西。
因此有:

package main

import (
    "fmt"
)

type Person struct {
    Name string
    Age  int
}

func (P Person) Eat() {
    fmt.Println(P.Name, "可以吃肉和菜")
}

type Dog struct {
    Name string
    Age  int
}

func (D Dog) Eat() {
    fmt.Println(D.Name, "可以吃骨头")
}

type Cat struct {
    Name string
    Age  int
}

func (C Cat) Eat() {
    fmt.Println(C.Name, "可以吃鱼")
}

func main() {
    person := Person{Name: "李华"}
    person.Eat() // 李华 可以吃肉和菜
    dog := Dog{Name: "旺财"}
    dog.Eat() // 旺财 可以吃骨头
    cat := Cat{Name: "叮当"}
    cat.Eat() // 叮当 可以吃鱼
}

可以看到这里实例化了三个对象,执行了三次“对象.方法”的操作。这里只存在Person、Dog、Cat三种类型,但是后续如果增加更多的类型,那么每种类型都需要经过”实例化、对象.方法”的步骤。
引入接口,接口的定义为:接口是一组方法的集合,定义对象的行为规范,只定义不实现,实现规范的细节由对象绑定的方法决定。
加入如下代码:

type Eater interface {
    Eat() 
} // 定义一个Eater接口,拥有Eat函数

func Eat_Some(E Eater ) {
    E.Eat()
} // 定义一个以Eater接口为入参的函数,函数内调用了接口中的Eat函数

此时main函数变为

func main() {
    Eat_Some(Person{Name: "李华"}) // 李华 可以吃肉和菜
    Eat_Some(Dog{Name: "旺财"}) // 旺财 可以吃骨头
    Eat_Some(Cat{Name: "叮当"}) // 叮当 可以吃鱼
}

我们的需求是:“需要他们分别做出Eat的动作,来记录他们吃的东西”,我们把他们的Eat——具有相同动作,却又有不同表现——抽象出来,只关注动作的实现,形成接口。这样通过Eat_Some函数,传入不同的类,执行同一动作,完成了不同的操作,从而实现了多态。


未引入接口

引入接口

由图可以看出,抽象出来的接口位于动作实现层和对象实例化层的中间,为一个中间层,能够有效的解离定义和实现,减弱耦合。
最后附上源码:

package main

import (
    "fmt"
)

type Eater interface {
    Eat()
} // 定义一个接口

type Person struct {
    Name string
    Age  int
}

func (P Person) Eat() {
    fmt.Println(P.Name, "可以吃肉和草")
}

type Dog struct {
    Name string
    Age  int
}

func (D Dog) Eat() {
    fmt.Println(D.Name, "可以吃骨头")
}

type Cat struct {
    Name string
    Age  int
}

func (C Cat) Eat() {
    fmt.Println(C.Name, "可以吃鱼")
}

func Eat_Some(E Eater) {
    E.Eat()
} // 定义一个以接口为入参的函数,函数内调用了接口中的方法

func main() {
    Eat_Some(Person{Name: "李华"}) // 李华 可以吃肉和菜
    Eat_Some(Dog{Name: "旺财"}) // 旺财 可以吃骨头
    Eat_Some(Cat{Name: "叮当"}) // 叮当 可以吃鱼
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容