

Go语言实践模式 - 函数选项模式(Functional Options Pattern) - taadis
source link: https://www.cnblogs.com/taadis/p/go-functional-options-pattern.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

什么是函数选项模式
大家好,我是小白,有点黑的那个白。
最近遇到一个问题,因为业务需求,需要对接三方平台.
而三方平台提供的一些HTTP(S)接口都有统一的密钥生成规则要求.
为此我们封装了一个独立的包 xxx-go-sdk 以便维护和对接使用.
其中核心的部分是自定义HTTP Client,如下:
type Client struct {}
func (c *Client) do() {
// 实现统一的加密和签名逻辑
// 统一调用net/http
}
// 订单列表接口
func (c *Client) OrderList(){
c.do()
}
// 订单发货接口
func (c *Client) OrderDelivery(){
c.do()
}
// ... 其他接口
一些平台会要求appKey/appSecret等信息,所以Client结构体就变成了这样,这时参数还比较少, 而且是必填的参数,我们可以提供构造函数来明确指定。
type Client struct {
AppKey string
AppSecret string
}
func NewClient(appKey string, appSecret string) *Client {
c := new(Client)
c.AppKey = appKey
c.AppSecret = appSecret
return c
}
看起来很满足,但是当我们需要增加一个 Timeout 参数来控制超时呢?
或许你会说这还不简单,像下面一样再加一个参数呗
type Client struct {
AppKey string
AppSecret string
Timeout time.Duration
}
func NewClient(appKey string, appSecret string, timeout time.Duration) *Client {
c := new(Client)
c.AppKey = appKey
c.AppSecret = appSecret
c.Timeout = timeout
return c
}
那再加些其他的参数呢?那构造函数的参数是不是又长又串,而且每个参数不一定是必须的,有些参数我们有会考虑默认值的问题。
为此,勤劳但尚未致富的 gophers 们使用了总结一种实践模式
首先提取所有需要的参数到一个独立的结构体 Options,当然你也可以用 Configs 啥的.
type Options struct {
AppKey string
AppSecret string
}
然后为每个参数提供设置函数
func WithAppKey(appKey string) func(*Options) {
return func(o *Options) {
o.AppKey = appKey
}
}
func WithAppSecret(appSecret string) func(*Options) {
return func(o *Options) {
o.AppSecret = appSecret
}
}
这样我们就为每个参数设置了独立的设置函数。返回值 func(*Options)
看着有点不友好,我们提取下定义为单个 Option
调整一下代码
type Option func(*Options)
func WithAppKey(appKey string) Option {
return func(o *Options) {
o.AppKey = appKey
}
}
func WithAppSecret(appSecret string) Option {
return func(o *Options) {
o.AppSecret = appSecret
}
}
当我们需要添加更多的参数时,只需要在 Options 添加新的参数并添加新参数的设置函数即可。
比如现在要添加新的参数 Timeout
type Options struct {
AppKey string
AppSecret string
Timeout. time.Duration // 新增参数
}
// Timeout 的设置函数
func WithTimeout(timeout time.Duration) Option {
return func(o *Options) {
o.Timeout = timeout
}
}
这样后续不管新增多少参数,只需要新增配置项并添加独立的设置函数即可轻松扩展,并且不会影响原有函数的参数顺序和个数位置等。
至此,每个选项是区分开来了,那么怎么作用到我们的 Client 结构体上呢?
首先,配置选项都被提取到了 Options 结构体中,所以我们需要调整一下 Client 结构体的参数
type Client struct {
options *Options
}
其次,每一个选项函数返回 Option,那么任意多个就是 ...Option,我们调整一下构造函数 NewClient 的参数形式,改为可变参数,不在局限于固定顺序的几个参数。
func NewClient(options ...Option) *Client {
c := new(Client)
c.Options = ?
return c
}
然后循环遍历每个选项函数,来生成Client结构体的完整配置选项。
func NewClient(options ...Option) *Client {
opts := new(Options)
for _, o := range options {
o(opts)
}
c := new(Client)
c.Options = opts
return c
}
那么怎么调用呢?对于调用方而已,直接在调用构造函数NewClient()的参数内添加自己需要的设置函数(WithXXX)即可
client := NewClient(
WithAppKey("your-app-key"),
WithAppSecret("your-app-secret"),
)
当需要设置超时参数,直接添加 WithTimeout即可,比如设置3秒的超时
client := NewClient(
WithAppKey("your-app-key"),
WithAppSecret("your-app-secret"),
WithTimeout(3*time.Second),
)
配置选项的位置可以任意设置,不需要受常规的固定参数顺序约束。
可以看到,这种实践模式主要作用于配置选项,利用函数支持的特性来实现的,为此得名 Functional Options Pattern,优美的中国话叫做「函数选项模式」。
最后, 我们总结回顾一下在Go语言中函数选项模式的优缺点
- 支持多参数;
- 支持参数任意位置顺序;
- 支持默认值设置;
- 向后兼容,扩展性极佳;
- 用户使用行为一致, 体感良好.
这是特性,不是缺点 - -!
- 增加了Options结构和Option定义;
- 针对每个参数都有对应的设置函数,每个选项函数的实现代码量好像多了一些;
Recommend
-
40
函数选项 Functimional Options 在Go语言中是没有默认函数的,但是我们可以使用函数选项模式来优雅的解决这个问题。函数选项模式不仅仅可以解决默认函数的问题还可以解决大量参数造成的代码复杂的问题。使用这个模式的有点:...
-
6
Functional options on steroids Posted on...
-
6
Functional options for friendly APIs 函数式选项模式对于设计友好的API有着重要的作用,它将会影响到你的API后期的扩展以及往前的兼容问题。假如我...
-
4
Functional options in Go Pam The Webivore Internet-ivore, development-ivore, design-ivore, event-ivore, fun-ivore. Technology, fun, and Philadelphia....
-
8
Functional Java: How to do pattern matching in Java 8? Reading Time: 2 minutesIn this article, we would learn how we can d...
-
2
Reading Time: 2 minutes Hi, community, in this blog, we will be covering what is pattern matching, when should we use it, and at the end, we’ll compare it with if-else. What is Pattern Matching? Pattern Matching is one...
-
4
Mepuka Kessy Posted on Dec 14...
-
6
Go 编程模式:Functional Options Go 编程模式:Functional Options 在本篇文章中,我们来讨论一下Functional Options这个编程模式。这是一个函数式编程的应用案例,编程技巧也很好,是目前在Go语言中最流行的一种编程模式。但是,在我们正式讨论这...
-
3
Functional Options in Go: With Generic
-
7
Golang函数式选项(Functional Options)模式 2021-02-18 Golang 约 1753 字...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK