Golang Functional Options 来了解一下?
Posted 灭BUG
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang Functional Options 来了解一下?相关的知识,希望对你有一定的参考价值。
在开发或者学习源码过程中,不少人应该见过下面的代码片段
type Option func(opts *Options)
// 新建一个server,client,pool等
func NewXXX(name string, opts ...Option) {}
刚开始从java
转go
的时候,我看这些代码真的是看得一脸懵逼,看不懂这些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 发布!
以上是关于Golang Functional Options 来了解一下?的主要内容,如果未能解决你的问题,请参考以下文章
Golang函数式选项(Functional Options)模式
Go语言实践模式 - 函数选项模式(Functional Options Pattern)