go 语言中实现父类到子类的多态

作者: | 更新日期:

go 语言中没有多态。

本文首发于公众号:天空的代码世界,微信号:tiankonguse

零、背景

之前,曾让一个新同事使用 go 语言写一个工具,将一个 DB 表 A的数据同步到另外一个 DB,当然两个 DB 的表字段有变化,存在一个换算过程。 后来,我又让同事把表 B 也同步一下,那个同事回去也同步了。
再后来,我让同事反复同步了 A 表和 B 表的内容。

每次她同步数据都要花费不少时间,我有点诧异,就去看她的代码怎么实现。
原来每次我让同步不同的代码时,她都是修改代码,调整为另外一个表的结构,进行同步。

我教导到,这个最好实现成传入不同的参数就同步不同的表,每次修改代码成本很高。
如果她临时有事,想让其他同事同步数据就更麻烦了。

实现方案有两种,一种是最笨的方法,每个表实现一份代码,传入不同的参数,调用不同的函数即可。
另一个方案是使用面向对象的思想,复用大部分代码,go 里面应该是面向接口编程,可以研究一下。

她想了好久,想用面向对象的方法实现,结果最终两个都没实现。

再后来项目大调整,她做其他事情去了。
于是我要到这份代码进行重写,决定用面向对象的方法实现这个小工具。

一、架构设计

既然是 DB 表的数据同步,很容易可以想到架构是下面的样子。

定义一个接口和父类,父类只需要实现通用逻辑,以及最重要的核心调度逻辑。
子类实现具体的个性化逻辑。

不过实现过程中,也需要一些问题,导致无法按照传统的方式实现。

二、问题之多态

既然有父类,那父类需要调用子类的函数时怎么办呢?

如果是其他面向对象语言转型过来的,很容易想到多态。

但是 go 里面没有多态,或者说 go 里面没有继承的概念。
上面写的继承只能算作语法糖,子类已经与父类完全没关系了。

那怎么实现呢?

go 里面有接口,所以我们可以通过接口来实现多态。

具体就是看上面那张图。

在父类中定义了一个接口变量,在创建子类的时候,需要主动的把子类设置到父类的接口里面。

info := &irstBDInfo{}
info.Init(info)

这样父类需要调用子类的具体实现的时候,直接用过这个变量就可以调用了。

func (g *BaseDBInfo) Init(base *Base) {
  g.base = base
}
func (g *BaseDBInfo) Sync() {
  g.base.GetList()
}

就这样,我们间接实现了多态。

三、问题之子类数据差异

具体在实现这个父类的时候,发现还设计一个致命的问题:数据列表也是有具体的类型的。
A 表的数据列表是 A 表的结构,B 表的数据列表是 B 表的结构。

如何在父类储存下来,并在调度程序里循环调度呢?

这就涉及另外一个知识点:go 中所有类型都可以转化为 空接口interface {} 类型。

就像 java 中有 Object ,C 或 cpp 中有 void *

有了这个万能的类型,我们就可以在父类中定义一个万能的接口类型,所有的数据都转化为接口列表。
在需要使用的时候,在具体的子类里再转为具体的结构。

四、最后

就这样,就使用面向对象的方法设计出一个复用性比较高的小工具。

当然,这是我写的第一个 go 程序。

可能因为我对 go 的理解不够深,还有其他更简洁的方法。

如果你对 go 比较有经验,欢迎留言提出不一样的方法来,供我学习一下。

《完》

-EOF-

本文公众号:天空的代码世界
个人微信号:tiankonguse
QQ算法群:165531769(不止算法)
知识星球:不止算法

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

点击查看评论

关注公众号,接收最新消息

关注小密圈,学习各种算法

tiankonguse +
穿越