最近在看gin的配置,然后发现配置方式很独特,通过了解原来是一种函数选项模式实现的,今天就顺便给自己做个笔记
Go函数选项模式
函数选项式(Functional Options) 是一种模式,在该模式中,你可以声明一个不透明的 Option 类型,该类型在某些内部结构体中记录信息。你接受这些可变数量的选项,并根据内部结构上的选项记录的完整信息进行操作。
将此模式用于构造函数和其他公共 API 中的可选参数,你预计这些参数需要扩展,尤其是在这些函数上已经有三个或更多参数的情况下。适合多个可选参数,初始化结构体来用,
既保持了兼容性,而且每增加1个新属性只需要1个With函数即可,大大减少了修改代码的风险
举个栗子-配置问题
type DbServer struct {
User string
Password string
Port int
Host string
Charset string
MaxOpenConns int
}
//初始化一个Service
func NewDbServer(user string, password string, port int, host string) *DbServer {
return &DbServer{user, password, name, port, host}
}
但是有个问题,因为golang支持函数重载,加入我们DbServer结构体中的其他属性也需要设置为非必填,该怎么处理
- 增加更多的NewService函数
- 在修改当前NewServer的入参,增加需要设置的属性
比如:除了user, password, port, host为必选字段外,charset是可选,如果增加其他可选,又需要再次增加函数
func NewDbServerWithCharset(user string, password string, port int, host string, charset string) *DbServer {
return &DbServer{user, password, port, host, charset}
}
缺点:
1.创建太多的NewDbServer函数,增加开发量
2.代码冗余
3.无扩展性,如果再增加Server他属性呢
解决方式-使用函数选项模式
整个模式的实现分为三部分:
- 定义一个函数类型Options
- 定义一个New函数,可接收opts多个可选参数
- 用闭包方式为每个结构的可选属性设置With函数,主要的行为是给对应的DbServer结构体属性赋值
我们分别用栗子讲讲各步骤的具体实现
1.定义函数类型Option
type Option func(*DbServer)
2.闭包方式给每个结构体中的可选属性定义函数
func WithCharset(charset string) Option {
return func(s *DbServer) {
s.Charset = charset
}
}
func WithMaxOpenConns(maxOpenConns int) Option {
return func(s *DbServer) {
s.MaxOpenConns = maxOpenConns
}
}
3.定义NewOption
NewDbServer中的可选参数opts,类型是Option,也就是WithCharset, 或者WithMaxOpenConns。然后对参数进行遍历进行,执行option函数去对DbServer对应的属性进行修改
func NewDbServer(user string, password string, name string, port int, host string, opts ...Option) *Server {
//创建DbServer对象,并填写可选项的默认值
server := &DbServer{
User: user
Password: password
Port: port
Host: host
}
//都选项列表中每项都应用
for _, option := range opts {
option(server)
}
return s
}
使用的话就是
svr := New(
"username",
"password",
3306,
"xxx",
WithCharset("UTF-8"),
WithMaxOpenConns(100),
)
其实你会发现基本上框架的初始化都是使用了这种模式,比如go-micro
总结
想必大家看完后也基本上了解了个大概了,但是这种方式最好的适用场景还是多参数配置上,而且是那种可选参数配置,如果我们只有两三个参数,且无后续扩展的话就没必要这么用了,反而会让我们程序显得更复杂不容易懂,好了今天的分享就到这里了
【记录分享点滴】