前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang-函数选项模式

Golang-函数选项模式

原创
作者头像
小许code
发布2023-03-03 09:40:11
2440
发布2023-03-03 09:40:11
举报
文章被收录于专栏:小许code小许code

最近在看gin的配置,然后发现配置方式很独特,通过了解原来是一种函数选项模式实现的,今天就顺便给自己做个笔记

Go函数选项模式

函数选项式(Functional Options) 是一种模式,在该模式中,你可以声明一个不透明的 Option 类型,该类型在某些内部结构体中记录信息。你接受这些可变数量的选项,并根据内部结构上的选项记录的完整信息进行操作。

将此模式用于构造函数和其他公共 API 中的可选参数,你预计这些参数需要扩展,尤其是在这些函数上已经有三个或更多参数的情况下。适合多个可选参数,初始化结构体来用,

既保持了兼容性,而且每增加1个新属性只需要1个With函数即可,大大减少了修改代码的风险

举个栗子-配置问题

代码语言:javascript
复制
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结构体中的其他属性也需要设置为非必填,该怎么处理

  1. 增加更多的NewService函数
  2. 在修改当前NewServer的入参,增加需要设置的属性

比如:除了user, password, port, host为必选字段外,charset是可选,如果增加其他可选,又需要再次增加函数

代码语言:javascript
复制
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他属性呢

解决方式-使用函数选项模式

整个模式的实现分为三部分:

  1. 定义一个函数类型Options
  2. 定义一个New函数,可接收opts多个可选参数
  3. 用闭包方式为每个结构的可选属性设置With函数,主要的行为是给对应的DbServer结构体属性赋值

我们分别用栗子讲讲各步骤的具体实现

1.定义函数类型Option

代码语言:javascript
复制
type Option func(*DbServer)

2.闭包方式给每个结构体中的可选属性定义函数

代码语言:javascript
复制
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对应的属性进行修改

代码语言:javascript
复制
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
}

使用的话就是

代码语言:javascript
复制
svr := NewDbServer(
    "username",
    "password",
    3306,
    "xxx",
    WithCharset("UTF-8"),
    WithMaxOpenConns(100),
  )

其实你会发现基本上框架的初始化都是使用了这种模式,比如go-micro

go-micro中的使用
go-micro中的使用

总结

想必大家看完后也基本上了解了个大概了,但是这种方式最好的适用场景还是多参数配置上,而且是那种可选参数配置,如果我们只有两三个参数,且无后续扩展的话就没必要这么用了,反而会让我们程序显得更复杂不容易懂,好了今天的分享就到这里了

【记录分享点滴】

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Go函数选项模式
  • 举个栗子-配置问题
  • 解决方式-使用函数选项模式
  • 1.定义函数类型Option
  • 2.闭包方式给每个结构体中的可选属性定义函数
  • 3.定义NewOption
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档