打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
最有效的Golang结构配置模式
userphoto

2024.01.28 广东

关注

概览

    假如我们在日常工作中想为自己的团队或者在github等开源社区上提供一些库和模块,如果代码中有自定义结构体,那创建结构体的时候必然需要配置属性参数;这时动态灵活的配置不同的参数以及提供默认配置项就显得格外重要,使用函数式选项(functional options)模式就可以很好的解决这个问题。

配置化

type Server struct { maxConn int id string tls bool}
func NewServer(maxConn int, id string, tls bool) *Server { return &Server{ maxConn: maxConn, id: id, tls: tls, }}
func main() { server := NewServer(100, 'test', true) fmt.Println(server)}
运行结果:&{100 test true}

上面的例子中, 我们定义了一个结构体Server,并提供一个NewServer函数来创建Server。很显然,这样写的方式有两个比较突出的缺点存在:

  1. NewServer函数的参数是固定的

  2. 如果结构体Server的字段属性非常多,那么对应的NewServer函数参数也是一样非常多,这将会变得非常繁琐

  3. 没有默认的字段属性

这里,可能有人会说可以创建一个Option或者Config结构体来接收这些属性,例如上面的代码可以优化写成如下的模式:

type Opt struct { maxConn int id string tls bool}
type Server struct { opt *Opt}
func NewServer(opt *Opt) *Server { return &Server{ opt: opt, }}
func main() { server := NewServer(&Opt{ 100, 'test', true, }) fmt.Println(server.opt)}

其实这样写已经是很不错了,很多的开源库作者都是这样写,引入一个Option结构体来解决多个参数的问题。

函数式选项(functional options)模式

熟悉Java的同学都知道,平常开发中每写一个类都要写对应的get()/set()方法,其实Go的函数式选项也是类似这样的思想原理。

这里废话不多说,直接贴代码:

// OptFunc 定义一个OptFunc函数类型,用来更新Opttype OptFunc func(*Opt)
type Opt struct { maxConn int id string tls bool}
type Server struct { opt *Opt}
// update maxConnfunc withMaxConn(maxConn int) OptFunc { return func(opt *Opt) { opt.maxConn = maxConn }}
// update idfunc withId(id string) OptFunc { return func(opt *Opt) { opt.id = id }}
// update tlsfunc withTls(tls bool) OptFunc { return func(opt *Opt) { opt.tls = tls }}
// default configfunc defaultOpt() *Opt { return &Opt{maxConn: 10, id: 'test', tls: true}}
func NewServer(opts ...OptFunc) *Server { o := defaultOpt() for _, opt := range opts { opt(o) } return &Server{ opt: o, }}
func main() { server := NewServer(withId('update'), withTls(false), withMaxConn(100)) fmt.Println(server.opt)}运行结果:&{100 update false}
  • 首先定义一个定义一个OptFunc函数类型,用来更新Opt结构体;

type OptFunc func(*Opt)
  • 在配置化中说到的第三点缺点:没有默认配置,这里这样解决,直接创建一个函数 defaultOpt()来初始化Opt结构体

// default configfunc defaultOpt() *Opt {    return &Opt{maxConn: 10,       id:  'test',       tls: true}}
  • 模仿Javaset()方法,这里我用三个withXX函数来更新对应的属性,返回一个OptFunc

// update maxConnfunc withMaxConn(maxConn int) OptFunc { return func(opt *Opt) { opt.maxConn = maxConn }}
// update idfunc withId(id string) OptFunc { return func(opt *Opt) { opt.id = id }}
// update tlsfunc withTls(tls bool) OptFunc { return func(opt *Opt) { opt.tls = tls }}
  • 重写NewServer的入参,改用接收不定长的OptFunc,使函数参数接收更加灵活多变

func NewServer(opts ...OptFunc) *Server {    o := defaultOpt()    for _, opt := range opts {       opt(o)    }    return &Server{       opt: o,    }}

总结

如果有研究过GRPC源码的同学可能会发现,其使用的就是functional options模式。总结一下functional options的优点:

  • 可以不定长入参

  • 支持默认值

  • 很容易维护和扩展

functional options 的优点很多,但是有些简单的配置其实并不需要这样小题大作,使简单问题复杂化。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Apache Thrift  Go Tutorial
Android Native 内存泄漏系统化解决方案
matlab 7 GA工具箱_木子一车
第七章 C语言声明详解
详解C语言结构体中的函数指针
使Python代码的速度提高1000倍
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服