go 语言中没有多态,但是有接口。


零、背景

之前,曾让一个新同事使用 go 语言写一个工具,将一个 DB A 表的数据同步到另外一个 DB 中。

当然两个 DB 的表字段有变化,存在一个换算过程。 

后来,我又让同事把表 B 也同步一下,那个同事回去也同步了。
再后来,我让同事反复同步了 A 表和 B 表的内容。


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


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


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

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


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


一、架构设计

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

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

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


二、问题之多态

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

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

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

那怎么实现呢?


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

具体就是看上面那张图。

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

  1. info := &firstBDInfo{}

  2. info.Init(info)

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

  1. func (g *BaseDBInfo) Init(base *Base) {

  2. g.base = base

  3. }

  4. func (g *BaseDBInfo) Sync() {

  5. g.base.GetList()

  6. }

就这样,我们间接实现了父类伪多态调用子类函数了。


三、问题之子类数据差异

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

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


interface {}
Objectvoid *

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


四、最后

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

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

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

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

《完》

-EOF-

题图:来自朋友圈。

长按二维码,一起成长学习


▲ 长按关注,天天成长

觉得有帮助可以点击好看与转发,谢谢!