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
公众号ID:tiankonguse-code
本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。