Golang Functional Options 来了解一下?

在开发或者学习源码过程中,不少人应该见过下面的代码片段

type Option func(opts *Options)

// 新建一个server,client,pool等
func NewXXX(name string, opts ...Option) {}

刚开始从javago的时候,我看这些代码真的是看得一脸懵逼,看不懂这些option是什么,也不明白为什么需要它们的存在

直到后来,我才知道,这叫函数式选项(Functional Options)

函数式选项是Golang中实现简洁API的一种方式

在使用NewXXX函数构建struct的时候,struct中的属性并不都是必须的,这些非必须属性,在构建struct的过程中可以通过函数式选项的方式,实现更加简洁的API

假设需要实现一个协程池GPool,其中必备的属性有协程数量size,还有可选项:是否异步async,错误处理errorHandler,最大缓存任务数maxTaskNums,那么struct的设计应该如下

package pool

// Option 定义函数式选项
type Option func(options *Options)

// GPool 协程池
type GPool struct {
    size    int64 // 协程数量
    options *Options
}

type ErrorHandler func(err error)

// Options 将非必须的选项都放到这里
type Options struct {
    async    bool         // 是否支持异步提交任务
    handler  ErrorHandler // 任务执行出错时,回调该函数
    maxTasks int64        // 协程池所接受的最大缓存任务数
}

// NewGPool 新建协程池
func NewGPool(size int64, opts ...Option) *GPool {
    options := loadOpts(opts)
    return &GPool{
        size:    size,
        options: options,
    }
}

func loadOpts(opts []Option) *Options {
    options := &Options{}
    for _, opt := range opts {
        opt(options)
    }
    return options
}

func WithAsync(async bool) Option {
    return func(options *Options) {
        options.async = async
    }
}

func WithErrorHandler(handler ErrorHandler) Option {
    return func(options *Options) {
        options.handler = handler
    }
}

func WithMaxTasks(maxTasks int64) Option {
    return func(options *Options) {
        options.maxTasks = maxTasks
    }
}

如果需要创建一个协程池,协程数量为100,只需要这样写

p := pool.NewGPool(100)

如果需要创建一个协程池,协程数量为100并支持异步提交,只需要这样写

p := pool.NewGPool(100, pool.WithAsync(true))

如果需要穿件一个协程池,协程数量为100、支持异步提交,并且回调自定义错误处理,只需要这样写

p := pool.NewGPool(100,
    pool.WithAsync(true),
    pool.WithErrorHandler(func(err error) {
        // 处理任务执行过程中发生的error
    }),
)

这样的写法是不是感觉更加简洁?

如果不使用函数式选项,我们还可以怎么做?

第一种,直接构建struct,但是需要填写非常非常多的属性,对调用者并不友好

func NewGPool(size int64, async bool, handler ErrorHandler, maxTasks int64) *GPool {
    return &GPool{
        size:    size,
        options: &Options{
            async:    async,
            handler:  handler,
            maxTasks: maxTasks,
        },
    }
}

struct中的属性变得越来越多时候,这长长的函数签名,对于调用者而言,简直是噩梦般的存在

第二种,使用建造者模式

func (builder *GPoolBuilder) Builder(size int64) *GPoolBuilder {
    return &GPoolBuilder{p: &GPool{
        size: size,
        options: &Options{},
    }}
}

func (builder *GPoolBuilder) WithAsync(async bool) *GPoolBuilder {
    builder.p.options.async = async
    return builder
}

func (builder *GPoolBuilder) Build() *GPool {
    return builder.p
}

调用者使用经构建者模式封装后的API,还是非常舒服的

    builder := GPoolBuilder{}
    p := builder.Builder(100).WithAsync(true).Build()

但是,却要额外维护一份属于builder的代码,虽然使用简洁,但是具备一定的维护成本!!

总的来看,函数式选项还是最佳的选择方案,开发者通过它能够构建简洁,友好的API。

本文由博客一文多发平台 OpenWrite 发布!

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

推荐阅读更多精彩内容