golang-函数选项模式小记

本文介绍了Go语言中的函数选项模式,用于处理具有多个可选参数的构造函数或API。通过定义Option函数类型,创建闭包设置结构体属性的With函数,以及接受多个Option参数的New函数,可以避免因增加可选参数导致的函数重载和代码冗余,提高代码的扩展性和可维护性。这种模式常见于框架初始化,如 Gin 框架。
摘要由CSDN通过智能技术生成

  最近在看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结构体中的其他属性也需要设置为非必填,该怎么处理

  1. 增加更多的NewService函数
  2. 在修改当前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他属性呢

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

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

  1. 定义一个函数类型Options
  2. 定义一个New函数,可接收opts多个可选参数
  3. 用闭包方式为每个结构的可选属性设置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

总结

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

【记录分享点滴】

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值