两分钟让你明白Go中如何继承
最近在重构代码的时候,抽象了大量的接口。也使用这些抽象的接口做了很多伪继承的操作,极大的减少了代码冗余,同时也增加了代码的可读性。
然后随便搜了一下关于Go继承的文章,发现有的文章的代码量过多,并且代码format极其粗糙,命名极其随意,类似于A、B这种,让人看着看着就忘了到底是谁继承谁,我又要回去看一遍逻辑。
虽然只是样例代码,我认为仍然需要做到简洁、清晰以及明了。这也是我为什么要写这篇博客的原因。接下里在这里简单分享一下在Go中如何实现继承。
1. 简单的组合
说到继承我们都知道,在Go中没有extends
关键字,也就意味着Go并没有原生级别的继承支持。这也是为什么我在文章开头用了伪继承这个词。本质上,Go使用interface实现的功能叫组合,Go是使用组合来实现的继承,说的更精确一点,是使用组合来代替的继承,举个很简单的例子。
1.1 实现父类
我们用很容易理解的动物-猫来举例子,废话不多说,直接看代码。
type Animal struct { Name string } func (a *Animal) Eat() { fmt.Printf("%v is eating", a.Name) fmt.Println() } type Cat struct { *Animal } cat := &Cat{ Animal: &Animal{ Name: "cat", }, } cat.Eat() // cat is eating
1.2 代码分析
首先,我们实现了一个Animal的结构体,代表动物类。并声明了Name字段,用于描述动物的名字。
然后,实现了一个以Animal为receiver的Eat方法,来描述动物进食的行为。
最后,声明了一个Cat结构体,组合了Cat字段。再实例化一个猫,调用Eat方法,可以看到会正常的输出。
可以看到,Cat结构体本身没有Name字段,也没有去实现Eat方法。唯一有的就是组合了Animal父类,至此,我们就证明了已经通过组合实现了继承。
2. 优雅的组合
熟悉Go的人看到上面的代码可能会发出如下感叹
这也太粗糙了吧 -- By 鲁迅:我没说过这句话
的确,上面的仅仅是为了给还没有了解过Go组合的人看的。作为一个简单的例子来理解Go的组合继承,这是完全没有问题的 。但如果要运用在真正的开发中,那还是远远不够的。
举个例子,我如果是这个抽象类的使用者,我拿到animal类不能一目了然的知道这个类干了什么,有哪些方法可以调用。以及,没有统一的初始化方式,这意味着凡是涉及到初始化的地方都会有重复代码。如果后期有初始化相关的修改,那么只有一个一个挨着改。所以接下来,我们对上述的代码做一些优化。
2.1 抽象接口
接口用于描述某个类的行为。例如,我们即将要抽象的动物接口就会描述作为一个动物,具有哪些行为。常识告诉我们,动物可以进食(Eat),可以发出声音(bark),可以移动(move)等等。这里有一个很有意思的类比。
接口就像是一个招牌,比如一家星巴克。星巴克就是一个招牌(接口)。
你看到这个招牌会想到什么?美式?星冰乐?抹茶拿铁?又或者是拿铁,甚至是店内的装修风格。
这就是一个好的接口应该达到的效果,同样这也是为什么我们需要抽象接口。
// 模拟动物行为的接口 type IAnimal interface { Eat() // 描述吃的行为 } // 动物 所有动物的父类 type Animal struct { Name string } // 动物去实现IAnimal中描述的吃的接口 func (a *Animal) Eat() { fmt.Printf("%v is eating\n", a.Name) } // 动物的构造函数 func newAnimal(name string) *Animal { return &Animal{ Name: name, } } // 猫的结构体 组合了animal type Cat struct { *Animal } // 实现猫的构造函数 初始化animal结构体 func newCat(name string) *Cat { return &Cat{ Animal: newAnimal(name), } } cat := newCat("cat") cat.Eat() // cat is eating
在Go中其实没有关于构造函数的定义。例如我们在Java中可以使用构造函数来初始化变量,举个很简单的例子,Integer num = new Integer(1)
。而在Go中就需要使用者自己通过结构体的初始化来模拟构造函数的实现。
然后在这里我们实现子类Cat,使用组合的方式代替继承,来调用Animal中的方法。运行之后我们可以看到,Cat结构体中并没有Name字段,也没有实现Eat方法,但是仍然可以正常运行。这证明我们已经通过组合的方式了实现了继承。
2.2 重载方法
// 猫结构体IAnimal的Eat方法 func (cat *Cat) Eat() { fmt.Printf("children %v is eating\n", cat.Name) } cat.Eat() // children cat is eating
可以看到,Cat结构体已经重载了Animal中的Eat方法,这样就实现了重载。
2.3 参数多态
什么意思呢?举个例子,我们要如何在Java中解决函数的参数多态问题?熟悉Java的可能会想到一种解决方案,那就是通配符。用一句话概括,使用了通配符可以使该函数接收某个类的所有父类型或者某个类的所有子类型。但是我个人认为对于不熟悉Java的人来说,可读性不是特别友好。
而在Go中,就十分方便了。
func check(animal IAnimal) { animal.Eat() }
在这个函数中就可以处理所有组合了Animal的单位类型,对应到Java中就是上界通配符,即一个可以处理任何特定类型以及是该特定类型的派生类的通配符,再换句人话,啥动物都能处理。
3. 总结
凡事都有两面性,做优化也不例外。大量的抽象接口的确可以精简代码,让代码看起来十分优雅、舒服。但是同样,这会给其他不熟悉的人review代码造成理解成本。想象你看某段代码,全是接口,点了好几层才能看到实现。更有的,往下找着找着突然就在另一个接口处断掉了,必须要手动的去另一个注册的地方去找。
这就是我认为优化的时候要面临的几个问题:
- 优雅
- 可读
- 性能
有的时候我们很难做到三个方面都兼顾,例如这样写代码看起来很难受,但是性能要比优雅的代码好。再例如,这样写看起来很优雅,但是可读性很差等等。
还是引用我之前博客中经常写的一句话
适合自己的才是最好的
这种时候只能根据自己项目的特定情况,选择最适合你的解决方案。没有万能的解决方案。
微信公众号: SH的全栈笔记(或直接在添加公众号界面搜索微信号LunhaoHu)
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
《交互式分析六脉神剑》之真正的秒级交互式响应
hi,大家好,今天为大家带来《交互式分析六脉神剑》之第三剑中冲剑--秒级交互式响应。第一剑:5分钟学会交互式分析?!第二剑:《交互式分析六脉神剑》之HoloStudio初体验 金庸武侠中的中冲剑是指:右手中指—阳明—胃经—中冲剑,其特点:大开大阖,气势雄迈。正好对应交互式分析的核心特点之一秒级交互式响应,今天小编就为大家介绍,秒级交互式响应如何体现在具体的数据开发实践中。 在离线大数据场景上,MaxCompute拥有着举足轻重的地位,但使用过MaxCompute的开发者们都会发现,针对简单查询能够满足业务要求,但是随着数量增多,查询query变得复杂时,响应速度会变得特别慢,满足不了实时交互的要求。而众所周知,交互式分析的核心功能之一是对MaxCompute离线数据加速查询。具体的加速体现在以下两个方面:(本案例均采用HoloStudio来进行演示,关于HoloStudio的介绍可参见HoloStudio简介) 简单场景 MaxCompute直接查询 针对简单查询场景,可以直接使用交互式分析进行查询,无需数据导入导出,就能实现实时查询。示例如下:在MaxCompute中有一张小表(数据...
- 下一篇
函数式接口
函数式接口 定义 函数式接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口; 函数式接口可以被隐式转换为Lambda表达式; 自定义函数式接口 @FunctionalInterface interface GreetingService { void sayMessage(String message); } 函数式接口种类 1.8 之前已有的 java.lang.Runnable java.util.concurrent.Callable java.security.PrivilegedAction java.util.Comparator java.io.FileFilter java.nio.file.PathMatcher java.lang.reflect.InvocationHandler java.beans.PropertyChangeListener java.awt.event.ActionListener javax.swing.event.ChangeListener 1.8 新增的 java.util.function function中包含很多...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Mario游戏-低调大师作品
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G