驱动开发在Golang中的应用

前言

在了解表驱动开发之前,有一个概念需要了解以下,那就是圈复杂度,又叫循环复杂度,那么什么是圈复杂度呢?

维基百科给出的解释是:圈复杂度是用来度量程序复杂度的,与时间复杂度空间复杂度不同的是,圈复杂度是从程序的控制流程唯独来进行度量的,它指程序的控制流程图中,若将结束点到起始点再增加一个边时,控制流程图中圈(几个边形成的封闭路径)的个数。

场景引入

几乎每个系统中都少不了登录功能,如果登录模块提供多种登录方式(如微信、Apple、Google、用户名/密码、Token等),那么在代码实现中你会怎么实现呢?相信很多人会采取如下方式:

type Platform uint8

const (
    Wechat Platform = iota + 1
    Apple
    Account
)

func Login(platform Platform, loginParam interface{}) (err error) {
    switch platform {
    case Wechat:
        return ByWechat(loginParam)
    case Apple:
        return ByApple(loginParam)
    case Account:
        return ByAccount(loginParam)
    default:
        // err
        return
    }
}

func ByWechat(param interface{}) (err error) {
    // logic
    return
}

func ByApple(param interface{}) (err error) {
    // logic
    return
}

func ByAccount(param interface{}) (err error) {
    // logic
    return
}

或者说是定义一个登录的方法集(接口),然后不同的方式定义不同的结构体,每个结构体实现登录方法集,最后在统一的登录入口处同样通过switch来选择不同的方法集载体。

尽管这样实现没问题,但是值得思考的的一个点是:如果有更多的登录方式,那么就需要在switch中添加更多的case,这样下去的结果就是代码难免会越来越显得臃肿,对于功能复杂(代码量大)的模块来说甚至越往后会越难维护,那么如何采取一种看起来美观,且易于维护的实现方式呢?

这里需要插一句,如果代码中存在很多ifswitch的话,会使代码的圈复杂度上升,即让代码变得不那么可读或者维护性不高。

如何解决?

此时我们可以通过表驱动的方式来优化该功能的实现。什么是表驱动呢?顾名思义,就是通过(查)表的方法来改变旧有的逻辑(if...else/switch)语句,尤其是在业务中对于不同途径的选择存在大量的逻辑语句时,可以考虑是否可以通过表驱动的方法来实现。

那么对于上面提到的多种登录功能,我们可以这样实现:

代码目录
  1. login.go
package login

import "errors"

type Platform uint8

const (
    Wechat Platform = iota + 1
    Apple
    Account
)

type ILogin interface {
    BeforeLogin(interface{})
    Login(interface{})
    AfterLogin(interface{})
}

var (
    m = make(map[Platform]ILogin)
)

func Register(platform Platform, method ILogin) {
    // 因为是在每个package中的init函数调用,所以不需要加锁
    // 如果需要动态添加,这里需要考虑并发
    m[platform] = method
}

func Login(platform Platform, param interface{}) (err error) {
    iface, ok := m[platform]
    if !ok {
        err = errors.New("invalid platform")
        return
    }
    iface.BeforeLogin(param)
    iface.Login(param)
    iface.AfterLogin(param)
    return
}

  1. account.go
package account

import "login"

type accountStruct struct {
    // field
}

func init() {
    login.Register(login.Account, &accountStruct{})
}

func (a *accountStruct) BeforeLogin(interface{}) {

}

func (a *accountStruct) Login(interface{}) {

}

func (a *accountStruct) AfterLogin(interface{}) {

}
  1. apple.go
package apple

import "login"

type appleStruct struct {
    // field
}

func init() {
    login.Register(login.Apple, &appleStruct{})
}

func (a *appleStruct) BeforeLogin(interface{}) {

}

func (a *appleStruct) Login(interface{}) {

}

func (a *appleStruct) AfterLogin(interface{}) {

}
  1. wechat.go
package wechat

import "login"

type wechatStruct struct {
    // field
}

func init() {
    login.Register(login.Wechat, &wechatStruct{})
}

func (a *wechatStruct) BeforeLogin(interface{}) {

}

func (a *wechatStruct) Login(interface{}) {

}

func (a *wechatStruct) AfterLogin(interface{}) {

}

这样看起来代码是否更加清晰直观呢?如果需要添加更多的登录方式只需要在新的package中实现对应的API,同时在init函数中注册对应的登录方式,即可在入口函数处调用!

最后

这种写法在grpc-go中也能找到。

资料参考

《Wiki百科》
《Go语言高级编程》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容