开发者学堂课程【Go 语言核心编程 - 面向对象、文件、单元测试、反射、TCP 编程:实现接口和继承比较(1)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/626/detail/9825
实现接口和继承比较(1)
内容简介
一、接口和继承比较的举例说明
二、例题讲解
三、总结说明
一、接口和继承比较的举例说明
前面我们已经将接口的概念与应用进行了介绍,并且举了一些案例进行讲解,但可能大家对接口和继承这两个概念容易混淆,所以我们来了解一下接口和继承之间有什么区别。
例题介绍
图示有一只小猴子,假设这只小猴子继承了老猴子的所有能力,这时候老猴子所拥有的能力,包括它的字段、包括他的方法等就会自动的被小猴子所继承,而这个小猴子不需要做任何处理就可以得到这个老猴子的字段和他的方法。但是比如这个小猴子不安于现状,他可能除了会爬树,还希望像小鸟一样飞翔,像鱼一样游泳,这个时候就要通过接口的方式来增强这个小猴子的能力。可以这样理解,一个结构体A继承了另一个结构体B之后呢,那么这个结构体A就拥有了继承的结构体B的字段和方法,但是如果这个结构体A希望去扩展一些结构体B所不具备的方法,且不破坏两者的继承关系关系,就可以用接口的方式来实现。比如小猴子通过努力可以实现飞翔的功能,通过学习可以实现像小鱼一样游泳的功能,所以我们可以理解成接口是对继承的一种补充。
二、例题讲解
- 首先在 chapter11中新建一个文件夹 interfacevsextends,如何在文件夹下新建一个文件 main.go,输入共用代码:
package main
import(
"fmt"
)
写一个主函数:
func main(){
}
现在存在一个猴子结构体,输入:type Monkey struct {},类型为 struct,假设猴子有一个名字以及一个方法,假设是猴子生来就会爬树这样的方法,代码为:
type Monkey struct {
Name string
}
func (this*Monkey) c1imbing (){
fmt. PrintIn(this. Name,“生来会爬树”)
上述代码表示为 monkey 结构体绑定了一个方法 climbing。
- 再定义一个 Littlemonkey 结构体
type Littlemonkey struct {
Monkey
}
使用匿名结构体去继承 monkey 结构体的功能,此时我们可以直接为 Littlemonkey 结构体绑定 climbing 的方法,
- 创建一个 LittleMonkey 实例
monkey := LittleMonkey{
Monkey{
Name:”悟空”,
}
}
Littlemonkey 里有匿名结构体 monkey,名字为悟空,此时 Littlemonkey 可以直接调用 monkey 里的方法,因为Littlemonkey 是对 monkey 的继承,可以继承 monkey 的字段以及方法。
- 输入:monkey.climbing ()完成调用并进行运行,发现出现错误,检查更改,func (this*Monkey) c1imbing ()处漏加了括号,monkey := LittleMonkey,添加冒号使用类型推到,Name:”悟空”,处的逗号。修改完成没有错误后,完成运行。找到D盘目录下的 goproject 文件夹里的 src 文件夹,在src文件夹里点击 gocode 文件夹,找到刚刚写入的 chapter11文件夹,打开 interfacevsextends 文件夹,输入cmd后进入运行界面,输入 go run main.go,发现运行结果为一句话:悟空 生来会爬树。
- 上述内容在前面的课程已经讲过了,此时想要在上面的基础上进行扩展,想去学习小鸟飞翔,小鱼游泳的功能,作为设计者可以这样考虑,只需要在 monkey 这一层加入 flying、swimming 的方法,即添加以下代码:
func (this*Monkey) =flying{
fmt. PrintIn(this. Name,“生来会爬树”)
但是由于猴子本身是不会飞翔的,直接写入飞翔是不合理的,我们之所以提出上述需求是因为这一只小猴子比较特别,希望它可以学习到飞翔以及游泳的本领,即完成扩展功能,但并不是直接将方法绑定到小猴子这个结构体本身。此时既不想破坏继承关系的合理性同时又希望 Littlemonkey 具有 flying 的功能,就需要利用接口来完成上述需求,因此我们也可以说接口是对继承关系的补充。
- 进行接口的声明并写入方法 flying,代码为:
type BirdAble interface {
Flying()
}
- 下面希望 Littlemonkey 来实现上述接口,让小猴子学会飞的能力,但是并不影响 monkey 结构体。即让LittleMonkey 实现 Birdable 的接口,我们所说的实现接口,其实就是要实现接口里所声明的方法。
func (this *LittleMonkey) Flying() {
fmt. Println(this. Name,”通过学习,会飞翔")
}
此时此刻,Littlemonkey 实现了 Birdable 接口,小猴子可以进行飞翔并且不会对老猴子产生任何影响。
- 输入 monkey.flying()完成运行,在运行界面输入go run main.go,发现运行结果为:悟空 生来会爬树和悟空 通过学习,会飞翔。
相信大家可以体会到通过接口进行了功能的扩展,但不会影响继承体本身以及两者的继承关系
- 同样让 LittleMonkey 实现游泳的功能,需要再去生成一个接口,
type FishAble interface {
Swimming()
}
可以发现与 Birdable 接口的生成类似,所以说接口的生成是十分灵活的。
- 需要实现上面的方法,同样使用与 flying 相同的调用方法
func (this *LittleMonkey) Swimminging() {
fmt. Println(this. Name,”通过学习,会游泳")
}
- 输入 monkey.swimminging(),让小猴子结构体完成对 swimming方法的调用,在运行界面输入 go run main.go,发现运行结果为:悟空 生来会爬树、悟空 通过学习,会飞翔、悟空 通过学习,会游泳。
三、总结说明
实现接口可以在不破坏继承关系的基础上,对结构体进行功能的扩展。
1)当 A 结构体继承了 B 结构体,那么A结构就自动的继承了B结构体的字段和方法,并且可以直接使用
2)当 A 结构体需要扩展功能,同时不希望去破坏继承关系,则可以去实现某个接口即可,因此我们可以认为:实现接口是对继承机制的补充